• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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_database.h"
6 
7 #include <string>
8 
9 #include "base/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/stl_util.h"
12 #include "content/browser/service_worker/service_worker_database.pb.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace content {
16 
17 namespace {
18 
19 typedef ServiceWorkerDatabase::RegistrationData RegistrationData;
20 typedef ServiceWorkerDatabase::ResourceRecord Resource;
21 
22 struct AvailableIds {
23   int64 reg_id;
24   int64 res_id;
25   int64 ver_id;
26 
AvailableIdscontent::__anonb3f99cf60111::AvailableIds27   AvailableIds() : reg_id(-1), res_id(-1), ver_id(-1) {}
~AvailableIdscontent::__anonb3f99cf60111::AvailableIds28   ~AvailableIds() {}
29 };
30 
URL(const GURL & origin,const std::string & path)31 GURL URL(const GURL& origin, const std::string& path) {
32   EXPECT_TRUE(origin.is_valid());
33   EXPECT_EQ(origin, origin.GetOrigin());
34   GURL out(origin.spec() + path);
35   EXPECT_TRUE(out.is_valid());
36   return out;
37 }
38 
CreateResource(int64 resource_id,const GURL & url)39 Resource CreateResource(int64 resource_id, const GURL& url) {
40   EXPECT_TRUE(url.is_valid());
41   Resource resource;
42   resource.resource_id = resource_id;
43   resource.url = url;
44   return resource;
45 }
46 
CreateDatabase(const base::FilePath & path)47 ServiceWorkerDatabase* CreateDatabase(const base::FilePath& path) {
48   return new ServiceWorkerDatabase(path);
49 }
50 
CreateDatabaseInMemory()51 ServiceWorkerDatabase* CreateDatabaseInMemory() {
52   return new ServiceWorkerDatabase(base::FilePath());
53 }
54 
VerifyRegistrationData(const RegistrationData & expected,const RegistrationData & actual)55 void VerifyRegistrationData(const RegistrationData& expected,
56                             const RegistrationData& actual) {
57   EXPECT_EQ(expected.registration_id, actual.registration_id);
58   EXPECT_EQ(expected.scope, actual.scope);
59   EXPECT_EQ(expected.script, actual.script);
60   EXPECT_EQ(expected.version_id, actual.version_id);
61   EXPECT_EQ(expected.is_active, actual.is_active);
62   EXPECT_EQ(expected.has_fetch_handler, actual.has_fetch_handler);
63   EXPECT_EQ(expected.last_update_check, actual.last_update_check);
64 }
65 
VerifyResourceRecords(const std::vector<Resource> & expected,const std::vector<Resource> & actual)66 void VerifyResourceRecords(const std::vector<Resource>& expected,
67                            const std::vector<Resource>& actual) {
68   ASSERT_EQ(expected.size(), actual.size());
69   for (size_t i = 0; i < expected.size(); ++i) {
70     EXPECT_EQ(expected[i].resource_id, actual[i].resource_id);
71     EXPECT_EQ(expected[i].url, actual[i].url);
72   }
73 }
74 
75 }  // namespace
76 
TEST(ServiceWorkerDatabaseTest,OpenDatabase)77 TEST(ServiceWorkerDatabaseTest, OpenDatabase) {
78   base::ScopedTempDir database_dir;
79   ASSERT_TRUE(database_dir.CreateUniqueTempDir());
80   scoped_ptr<ServiceWorkerDatabase> database(
81       CreateDatabase(database_dir.path()));
82 
83   // Should be false because the database does not exist at the path.
84   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
85             database->LazyOpen(false));
86 
87   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true));
88 
89   database.reset(CreateDatabase(database_dir.path()));
90   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(false));
91 }
92 
TEST(ServiceWorkerDatabaseTest,OpenDatabase_InMemory)93 TEST(ServiceWorkerDatabaseTest, OpenDatabase_InMemory) {
94   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
95 
96   // Should be false because the database does not exist in memory.
97   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
98             database->LazyOpen(false));
99 
100   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true));
101   database.reset(CreateDatabaseInMemory());
102 
103   // Should be false because the database is not persistent.
104   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
105             database->LazyOpen(false));
106 }
107 
TEST(ServiceWorkerDatabaseTest,DatabaseVersion)108 TEST(ServiceWorkerDatabaseTest, DatabaseVersion) {
109   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
110   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true));
111 
112   // Opening a new database does not write anything, so its schema version
113   // should be 0.
114   int64 db_version = -1;
115   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
116             database->ReadDatabaseVersion(&db_version));
117   EXPECT_EQ(0u, db_version);
118 
119   // First writing triggers database initialization and bumps the schema
120   // version.
121   std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
122   std::vector<int64> newly_purgeable_resources;
123   ServiceWorkerDatabase::RegistrationData data;
124   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
125             database->WriteRegistration(data, resources,
126                                         &newly_purgeable_resources));
127 
128   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
129             database->ReadDatabaseVersion(&db_version));
130   EXPECT_LT(0, db_version);
131 }
132 
TEST(ServiceWorkerDatabaseTest,GetNextAvailableIds)133 TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
134   base::ScopedTempDir database_dir;
135   ASSERT_TRUE(database_dir.CreateUniqueTempDir());
136   scoped_ptr<ServiceWorkerDatabase> database(
137       CreateDatabase(database_dir.path()));
138 
139   GURL origin("http://example.com");
140 
141   // The database has never been used, so returns initial values.
142   AvailableIds ids;
143   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds(
144       &ids.reg_id, &ids.ver_id, &ids.res_id));
145   EXPECT_EQ(0, ids.reg_id);
146   EXPECT_EQ(0, ids.ver_id);
147   EXPECT_EQ(0, ids.res_id);
148 
149   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true));
150   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds(
151       &ids.reg_id, &ids.ver_id, &ids.res_id));
152   EXPECT_EQ(0, ids.reg_id);
153   EXPECT_EQ(0, ids.ver_id);
154   EXPECT_EQ(0, ids.res_id);
155 
156   // Writing a registration bumps the next available ids.
157   std::vector<Resource> resources;
158   RegistrationData data1;
159   std::vector<int64> newly_purgeable_resources;
160   data1.registration_id = 100;
161   data1.scope = URL(origin, "/foo");
162   data1.script = URL(origin, "/script1.js");
163   data1.version_id = 200;
164   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
165             database->WriteRegistration(data1, resources,
166                                         &newly_purgeable_resources));
167 
168   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds(
169       &ids.reg_id, &ids.ver_id, &ids.res_id));
170   EXPECT_EQ(101, ids.reg_id);
171   EXPECT_EQ(201, ids.ver_id);
172   EXPECT_EQ(0, ids.res_id);
173 
174   // Writing a registration whose ids are lower than the stored ones should not
175   // bump the next available ids.
176   RegistrationData data2;
177   data2.registration_id = 10;
178   data2.scope = URL(origin, "/bar");
179   data2.script = URL(origin, "/script2.js");
180   data2.version_id = 20;
181   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
182             database->WriteRegistration(data2, resources,
183                                         &newly_purgeable_resources));
184 
185   // Close and reopen the database to verify the stored values.
186   database.reset(CreateDatabase(database_dir.path()));
187 
188   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds(
189       &ids.reg_id, &ids.ver_id, &ids.res_id));
190   EXPECT_EQ(101, ids.reg_id);
191   EXPECT_EQ(201, ids.ver_id);
192   EXPECT_EQ(0, ids.res_id);
193 }
194 
TEST(ServiceWorkerDatabaseTest,GetOriginsWithRegistrations)195 TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
196   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
197 
198   std::set<GURL> origins;
199   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
200             database->GetOriginsWithRegistrations(&origins));
201   EXPECT_TRUE(origins.empty());
202 
203   std::vector<Resource> resources;
204   std::vector<int64> newly_purgeable_resources;
205 
206   GURL origin1("http://example.com");
207   RegistrationData data1;
208   data1.registration_id = 123;
209   data1.scope = URL(origin1, "/foo");
210   data1.script = URL(origin1, "/script1.js");
211   data1.version_id = 456;
212   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
213             database->WriteRegistration(data1, resources,
214                                         &newly_purgeable_resources));
215 
216   GURL origin2("https://www.example.com");
217   RegistrationData data2;
218   data2.registration_id = 234;
219   data2.scope = URL(origin2, "/bar");
220   data2.script = URL(origin2, "/script2.js");
221   data2.version_id = 567;
222   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
223             database->WriteRegistration(data2, resources,
224                                         &newly_purgeable_resources));
225 
226   GURL origin3("https://example.org");
227   RegistrationData data3;
228   data3.registration_id = 345;
229   data3.scope = URL(origin3, "/hoge");
230   data3.script = URL(origin3, "/script3.js");
231   data3.version_id = 678;
232   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
233             database->WriteRegistration(data3, resources,
234                                         &newly_purgeable_resources));
235 
236   // |origin3| has two registrations.
237   RegistrationData data4;
238   data4.registration_id = 456;
239   data4.scope = URL(origin3, "/fuga");
240   data4.script = URL(origin3, "/script4.js");
241   data4.version_id = 789;
242   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
243             database->WriteRegistration(data4, resources,
244                                         &newly_purgeable_resources));
245 
246   origins.clear();
247   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
248             database->GetOriginsWithRegistrations(&origins));
249   EXPECT_EQ(3U, origins.size());
250   EXPECT_TRUE(ContainsKey(origins, origin1));
251   EXPECT_TRUE(ContainsKey(origins, origin2));
252   EXPECT_TRUE(ContainsKey(origins, origin3));
253 
254   // |origin3| has another registration, so should not remove it from the
255   // unique origin list.
256   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
257             database->DeleteRegistration(data4.registration_id, origin3,
258                                          &newly_purgeable_resources));
259 
260   origins.clear();
261   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
262             database->GetOriginsWithRegistrations(&origins));
263   EXPECT_EQ(3U, origins.size());
264   EXPECT_TRUE(ContainsKey(origins, origin1));
265   EXPECT_TRUE(ContainsKey(origins, origin2));
266   EXPECT_TRUE(ContainsKey(origins, origin3));
267 
268   // |origin3| should be removed from the unique origin list.
269   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
270             database->DeleteRegistration(data3.registration_id, origin3,
271                                          &newly_purgeable_resources));
272 
273   origins.clear();
274   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
275             database->GetOriginsWithRegistrations(&origins));
276   EXPECT_EQ(2U, origins.size());
277   EXPECT_TRUE(ContainsKey(origins, origin1));
278   EXPECT_TRUE(ContainsKey(origins, origin2));
279 }
280 
TEST(ServiceWorkerDatabaseTest,GetRegistrationsForOrigin)281 TEST(ServiceWorkerDatabaseTest, GetRegistrationsForOrigin) {
282   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
283 
284   GURL origin1("http://example.com");
285   GURL origin2("https://www.example.com");
286   GURL origin3("https://example.org");
287 
288   std::vector<RegistrationData> registrations;
289   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
290             database->GetRegistrationsForOrigin(origin1, &registrations));
291   EXPECT_TRUE(registrations.empty());
292 
293   std::vector<Resource> resources;
294   std::vector<int64> newly_purgeable_resources;
295 
296   RegistrationData data1;
297   data1.registration_id = 100;
298   data1.scope = URL(origin1, "/foo");
299   data1.script = URL(origin1, "/script1.js");
300   data1.version_id = 1000;
301   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
302             database->WriteRegistration(data1, resources,
303                                         &newly_purgeable_resources));
304 
305   RegistrationData data2;
306   data2.registration_id = 200;
307   data2.scope = URL(origin2, "/bar");
308   data2.script = URL(origin2, "/script2.js");
309   data2.version_id = 2000;
310   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
311             database->WriteRegistration(data2, resources,
312                                         &newly_purgeable_resources));
313 
314   RegistrationData data3;
315   data3.registration_id = 300;
316   data3.scope = URL(origin3, "/hoge");
317   data3.script = URL(origin3, "/script3.js");
318   data3.version_id = 3000;
319   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
320             database->WriteRegistration(data3, resources,
321                                         &newly_purgeable_resources));
322 
323   // |origin3| has two registrations.
324   RegistrationData data4;
325   data4.registration_id = 400;
326   data4.scope = URL(origin3, "/fuga");
327   data4.script = URL(origin3, "/script4.js");
328   data4.version_id = 4000;
329   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
330             database->WriteRegistration(data4, resources,
331                                         &newly_purgeable_resources));
332 
333   registrations.clear();
334   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
335             database->GetRegistrationsForOrigin(origin3, &registrations));
336   EXPECT_EQ(2U, registrations.size());
337   VerifyRegistrationData(data3, registrations[0]);
338   VerifyRegistrationData(data4, registrations[1]);
339 }
340 
TEST(ServiceWorkerDatabaseTest,GetAllRegistrations)341 TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) {
342   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
343 
344   std::vector<RegistrationData> registrations;
345   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
346             database->GetAllRegistrations(&registrations));
347   EXPECT_TRUE(registrations.empty());
348 
349   std::vector<Resource> resources;
350   std::vector<int64> newly_purgeable_resources;
351 
352   GURL origin1("http://www1.example.com");
353   RegistrationData data1;
354   data1.registration_id = 100;
355   data1.scope = URL(origin1, "/foo");
356   data1.script = URL(origin1, "/script1.js");
357   data1.version_id = 1000;
358   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
359             database->WriteRegistration(data1, resources,
360                                         &newly_purgeable_resources));
361 
362   GURL origin2("http://www2.example.com");
363   RegistrationData data2;
364   data2.registration_id = 200;
365   data2.scope = URL(origin2, "/bar");
366   data2.script = URL(origin2, "/script2.js");
367   data2.version_id = 2000;
368   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
369             database->WriteRegistration(data2, resources,
370                                         &newly_purgeable_resources));
371 
372   GURL origin3("http://www3.example.com");
373   RegistrationData data3;
374   data3.registration_id = 300;
375   data3.scope = URL(origin3, "/hoge");
376   data3.script = URL(origin3, "/script3.js");
377   data3.version_id = 3000;
378   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
379             database->WriteRegistration(data3, resources,
380                                         &newly_purgeable_resources));
381 
382   // |origin3| has two registrations.
383   RegistrationData data4;
384   data4.registration_id = 400;
385   data4.scope = URL(origin3, "/fuga");
386   data4.script = URL(origin3, "/script4.js");
387   data4.version_id = 4000;
388   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
389             database->WriteRegistration(data4, resources,
390                                         &newly_purgeable_resources));
391 
392   registrations.clear();
393   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
394             database->GetAllRegistrations(&registrations));
395   EXPECT_EQ(4U, registrations.size());
396   VerifyRegistrationData(data1, registrations[0]);
397   VerifyRegistrationData(data2, registrations[1]);
398   VerifyRegistrationData(data3, registrations[2]);
399   VerifyRegistrationData(data4, registrations[3]);
400 }
401 
TEST(ServiceWorkerDatabaseTest,Registration_Basic)402 TEST(ServiceWorkerDatabaseTest, Registration_Basic) {
403   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
404 
405   GURL origin("http://example.com");
406   RegistrationData data;
407   data.registration_id = 100;
408   data.scope = URL(origin, "/foo");
409   data.script = URL(origin, "/script.js");
410   data.version_id = 200;
411 
412   std::vector<Resource> resources;
413   resources.push_back(CreateResource(1, URL(origin, "/resource1")));
414   resources.push_back(CreateResource(2, URL(origin, "/resource2")));
415 
416   // Write a resource to the uncommitted list to make sure that writing
417   // registration removes resource ids associated with the registration from
418   // the uncommitted list.
419   std::set<int64> uncommitted_ids;
420   uncommitted_ids.insert(resources[0].resource_id);
421   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
422             database->WriteUncommittedResourceIds(uncommitted_ids));
423   std::set<int64> uncommitted_ids_out;
424   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
425             database->GetUncommittedResourceIds(&uncommitted_ids_out));
426   EXPECT_EQ(uncommitted_ids, uncommitted_ids_out);
427 
428   std::vector<int64> newly_purgeable_resources;
429   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
430             database->WriteRegistration(data, resources,
431                                         &newly_purgeable_resources));
432 
433   // Make sure that the registration and resource records are stored.
434   RegistrationData data_out;
435   std::vector<Resource> resources_out;
436   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
437             database->ReadRegistration(
438       data.registration_id, origin, &data_out, &resources_out));
439   VerifyRegistrationData(data, data_out);
440   VerifyResourceRecords(resources, resources_out);
441 
442   // Make sure that the resource is removed from the uncommitted list.
443   uncommitted_ids_out.clear();
444   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
445             database->GetUncommittedResourceIds(&uncommitted_ids_out));
446   EXPECT_TRUE(uncommitted_ids_out.empty());
447 
448   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
449             database->DeleteRegistration(data.registration_id, origin,
450                                          &newly_purgeable_resources));
451   ASSERT_EQ(resources.size(), newly_purgeable_resources.size());
452   for (size_t i = 0; i < resources.size(); ++i)
453     EXPECT_EQ(newly_purgeable_resources[i], resources[i].resource_id);
454 
455   // Make sure that the registration and resource records are gone.
456   resources_out.clear();
457   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
458             database->ReadRegistration(
459                 data.registration_id, origin, &data_out, &resources_out));
460   EXPECT_TRUE(resources_out.empty());
461 
462   // Resources should be purgeable because these are no longer referred.
463   std::set<int64> purgeable_ids_out;
464   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
465             database->GetPurgeableResourceIds(&purgeable_ids_out));
466   EXPECT_EQ(2u, purgeable_ids_out.size());
467   EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources[0].resource_id));
468   EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources[1].resource_id));
469 }
470 
TEST(ServiceWorkerDatabaseTest,Registration_Overwrite)471 TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) {
472   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
473 
474   GURL origin("http://example.com");
475   RegistrationData data;
476   data.registration_id = 100;
477   data.scope = URL(origin, "/foo");
478   data.script = URL(origin, "/script.js");
479   data.version_id = 200;
480 
481   std::vector<Resource> resources1;
482   resources1.push_back(CreateResource(1, URL(origin, "/resource1")));
483   resources1.push_back(CreateResource(2, URL(origin, "/resource2")));
484   std::vector<int64> newly_purgeable_resources;
485 
486   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
487             database->WriteRegistration(data, resources1,
488                                         &newly_purgeable_resources));
489   EXPECT_TRUE(newly_purgeable_resources.empty());
490 
491   // Make sure that the registration and resource records are stored.
492   RegistrationData data_out;
493   std::vector<Resource> resources_out;
494   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration(
495       data.registration_id, origin, &data_out, &resources_out));
496   VerifyRegistrationData(data, data_out);
497   VerifyResourceRecords(resources1, resources_out);
498 
499   // Update the registration.
500   RegistrationData updated_data = data;
501   updated_data.version_id = data.version_id + 1;
502   std::vector<Resource> resources2;
503   resources2.push_back(CreateResource(3, URL(origin, "/resource3")));
504   resources2.push_back(CreateResource(4, URL(origin, "/resource4")));
505 
506   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
507             database->WriteRegistration(updated_data, resources2,
508                                         &newly_purgeable_resources));
509   ASSERT_EQ(resources1.size(), newly_purgeable_resources.size());
510   for(size_t i = 0; i < resources1.size(); ++i)
511     EXPECT_EQ(newly_purgeable_resources[i], resources1[i].resource_id);
512 
513   // Make sure that |updated_data| is stored and resources referred from |data|
514   // is moved to the purgeable list.
515   resources_out.clear();
516   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration(
517       updated_data.registration_id, origin, &data_out, &resources_out));
518   VerifyRegistrationData(updated_data, data_out);
519   VerifyResourceRecords(resources2, resources_out);
520 
521   std::set<int64> purgeable_ids_out;
522   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
523             database->GetPurgeableResourceIds(&purgeable_ids_out));
524   EXPECT_EQ(2u, purgeable_ids_out.size());
525   EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources1[0].resource_id));
526   EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources1[1].resource_id));
527 }
528 
TEST(ServiceWorkerDatabaseTest,Registration_Multiple)529 TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
530   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
531   GURL origin("http://example.com");
532 
533   std::vector<int64> newly_purgeable_resources;
534 
535   // Add registration1.
536   RegistrationData data1;
537   data1.registration_id = 100;
538   data1.scope = URL(origin, "/foo");
539   data1.script = URL(origin, "/script1.js");
540   data1.version_id = 200;
541 
542   std::vector<Resource> resources1;
543   resources1.push_back(CreateResource(1, URL(origin, "/resource1")));
544   resources1.push_back(CreateResource(2, URL(origin, "/resource2")));
545   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
546             database->WriteRegistration(data1, resources1,
547                                         &newly_purgeable_resources));
548 
549   // Add registration2.
550   RegistrationData data2;
551   data2.registration_id = 101;
552   data2.scope = URL(origin, "/bar");
553   data2.script = URL(origin, "/script2.js");
554   data2.version_id = 201;
555 
556   std::vector<Resource> resources2;
557   resources2.push_back(CreateResource(3, URL(origin, "/resource3")));
558   resources2.push_back(CreateResource(4, URL(origin, "/resource4")));
559   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
560             database->WriteRegistration(data2, resources2,
561                                         &newly_purgeable_resources));
562 
563   // Make sure that registration1 is stored.
564   RegistrationData data_out;
565   std::vector<Resource> resources_out;
566   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration(
567       data1.registration_id, origin, &data_out, &resources_out));
568   VerifyRegistrationData(data1, data_out);
569   VerifyResourceRecords(resources1, resources_out);
570 
571   // Make sure that registration2 is also stored.
572   resources_out.clear();
573   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration(
574       data2.registration_id, origin, &data_out, &resources_out));
575   VerifyRegistrationData(data2, data_out);
576   VerifyResourceRecords(resources2, resources_out);
577 
578   std::set<int64> purgeable_ids_out;
579   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
580             database->GetPurgeableResourceIds(&purgeable_ids_out));
581   EXPECT_TRUE(purgeable_ids_out.empty());
582 
583   // Delete registration1.
584   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
585             database->DeleteRegistration(data1.registration_id, origin,
586                                          &newly_purgeable_resources));
587 
588   // Make sure that registration1 is gone.
589   resources_out.clear();
590   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
591             database->ReadRegistration(
592                 data1.registration_id, origin, &data_out, &resources_out));
593   EXPECT_TRUE(resources_out.empty());
594 
595   purgeable_ids_out.clear();
596   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
597             database->GetPurgeableResourceIds(&purgeable_ids_out));
598   EXPECT_EQ(2u, purgeable_ids_out.size());
599   EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources1[0].resource_id));
600   EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources1[1].resource_id));
601 
602   // Make sure that registration2 is still alive.
603   resources_out.clear();
604   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration(
605       data2.registration_id, origin, &data_out, &resources_out));
606   VerifyRegistrationData(data2, data_out);
607   VerifyResourceRecords(resources2, resources_out);
608 }
609 
TEST(ServiceWorkerDatabaseTest,UpdateVersionToActive)610 TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
611   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
612   GURL origin("http://example.com");
613 
614   std::vector<int64> newly_purgeable_resources;
615 
616   // Should be false because a registration does not exist.
617   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
618             database->UpdateVersionToActive(0, origin));
619 
620   // Add a registration.
621   RegistrationData data;
622   data.registration_id = 100;
623   data.scope = URL(origin, "/foo");
624   data.script = URL(origin, "/script.js");
625   data.version_id = 200;
626   data.is_active = false;
627   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
628             database->WriteRegistration(data, std::vector<Resource>(),
629                                         &newly_purgeable_resources));
630 
631   // Make sure that the registration is stored.
632   RegistrationData data_out;
633   std::vector<Resource> resources_out;
634   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
635             database->ReadRegistration(
636                 data.registration_id, origin, &data_out, &resources_out));
637   VerifyRegistrationData(data, data_out);
638   EXPECT_TRUE(resources_out.empty());
639 
640   // Activate the registration.
641   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
642             database->UpdateVersionToActive(data.registration_id, origin));
643 
644   // Make sure that the registration is activated.
645   resources_out.clear();
646   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
647             database->ReadRegistration(
648                 data.registration_id, origin, &data_out, &resources_out));
649   RegistrationData expected_data = data;
650   expected_data.is_active = true;
651   VerifyRegistrationData(expected_data, data_out);
652   EXPECT_TRUE(resources_out.empty());
653 
654   // Delete the registration.
655   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
656             database->DeleteRegistration(data.registration_id, origin,
657                                          &newly_purgeable_resources));
658 
659   // Should be false because the registration is gone.
660   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
661             database->UpdateVersionToActive(data.registration_id, origin));
662 }
663 
TEST(ServiceWorkerDatabaseTest,UpdateLastCheckTime)664 TEST(ServiceWorkerDatabaseTest, UpdateLastCheckTime) {
665   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
666   GURL origin("http://example.com");
667   std::vector<int64> newly_purgeable_resources;
668 
669   // Should be false because a registration does not exist.
670   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
671             database->UpdateLastCheckTime(0, origin, base::Time::Now()));
672 
673   // Add a registration.
674   RegistrationData data;
675   data.registration_id = 100;
676   data.scope = URL(origin, "/foo");
677   data.script = URL(origin, "/script.js");
678   data.version_id = 200;
679   data.last_update_check = base::Time::Now();
680   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
681             database->WriteRegistration(data, std::vector<Resource>(),
682                                         &newly_purgeable_resources));
683 
684   // Make sure that the registration is stored.
685   RegistrationData data_out;
686   std::vector<Resource> resources_out;
687   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
688             database->ReadRegistration(
689                 data.registration_id, origin, &data_out, &resources_out));
690   VerifyRegistrationData(data, data_out);
691   EXPECT_TRUE(resources_out.empty());
692 
693   // Update the last check time.
694   base::Time updated_time = base::Time::Now();
695   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
696             database->UpdateLastCheckTime(
697                 data.registration_id, origin, updated_time));
698 
699   // Make sure that the registration is updated.
700   resources_out.clear();
701   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
702             database->ReadRegistration(
703                 data.registration_id, origin, &data_out, &resources_out));
704   RegistrationData expected_data = data;
705   expected_data.last_update_check = updated_time;
706   VerifyRegistrationData(expected_data, data_out);
707   EXPECT_TRUE(resources_out.empty());
708 
709   // Delete the registration.
710   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
711             database->DeleteRegistration(data.registration_id, origin,
712                                          &newly_purgeable_resources));
713 
714   // Should be false because the registration is gone.
715   EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
716             database->UpdateLastCheckTime(
717                 data.registration_id, origin, base::Time::Now()));
718 }
719 
TEST(ServiceWorkerDatabaseTest,UncommittedResourceIds)720 TEST(ServiceWorkerDatabaseTest, UncommittedResourceIds) {
721   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
722 
723   // Write {1, 2, 3}.
724   std::set<int64> ids1;
725   ids1.insert(1);
726   ids1.insert(2);
727   ids1.insert(3);
728   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
729             database->WriteUncommittedResourceIds(ids1));
730 
731   std::set<int64> ids_out;
732   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
733             database->GetUncommittedResourceIds(&ids_out));
734   EXPECT_EQ(ids1, ids_out);
735 
736   // Write {2, 4}.
737   std::set<int64> ids2;
738   ids2.insert(2);
739   ids2.insert(4);
740   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
741             database->WriteUncommittedResourceIds(ids2));
742 
743   ids_out.clear();
744   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
745             database->GetUncommittedResourceIds(&ids_out));
746   std::set<int64> expected = base::STLSetUnion<std::set<int64> >(ids1, ids2);
747   EXPECT_EQ(expected, ids_out);
748 
749   // Delete {2, 3}.
750   std::set<int64> ids3;
751   ids3.insert(2);
752   ids3.insert(3);
753   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
754             database->ClearUncommittedResourceIds(ids3));
755 
756   ids_out.clear();
757   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
758             database->GetUncommittedResourceIds(&ids_out));
759   expected = base::STLSetDifference<std::set<int64> >(expected, ids3);
760   EXPECT_EQ(expected, ids_out);
761 }
762 
TEST(ServiceWorkerDatabaseTest,PurgeableResourceIds)763 TEST(ServiceWorkerDatabaseTest, PurgeableResourceIds) {
764   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
765 
766   // Write {1, 2, 3}.
767   std::set<int64> ids1;
768   ids1.insert(1);
769   ids1.insert(2);
770   ids1.insert(3);
771   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
772             database->WritePurgeableResourceIds(ids1));
773 
774   std::set<int64> ids_out;
775   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
776             database->GetPurgeableResourceIds(&ids_out));
777   EXPECT_EQ(ids1, ids_out);
778 
779   // Write {2, 4}.
780   std::set<int64> ids2;
781   ids2.insert(2);
782   ids2.insert(4);
783   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
784             database->WritePurgeableResourceIds(ids2));
785 
786   ids_out.clear();
787   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
788             database->GetPurgeableResourceIds(&ids_out));
789   std::set<int64> expected = base::STLSetUnion<std::set<int64> >(ids1, ids2);
790   EXPECT_EQ(expected, ids_out);
791 
792   // Delete {2, 3}.
793   std::set<int64> ids3;
794   ids3.insert(2);
795   ids3.insert(3);
796   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
797             database->ClearPurgeableResourceIds(ids3));
798 
799   ids_out.clear();
800   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
801             database->GetPurgeableResourceIds(&ids_out));
802   expected = base::STLSetDifference<std::set<int64> >(expected, ids3);
803   EXPECT_EQ(expected, ids_out);
804 }
805 
TEST(ServiceWorkerDatabaseTest,DeleteAllDataForOrigin)806 TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
807   scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
808   std::vector<int64> newly_purgeable_resources;
809 
810   // Data associated with |origin1| will be removed.
811   GURL origin1("http://example.com");
812   GURL origin2("http://example.org");
813 
814   // |origin1| has two registrations.
815   RegistrationData data1;
816   data1.registration_id = 10;
817   data1.scope = URL(origin1, "/foo");
818   data1.script = URL(origin1, "/script1.js");
819   data1.version_id = 100;
820 
821   std::vector<Resource> resources1;
822   resources1.push_back(CreateResource(1, URL(origin1, "/resource1")));
823   resources1.push_back(CreateResource(2, URL(origin1, "/resource2")));
824   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
825             database->WriteRegistration(data1, resources1,
826                                         &newly_purgeable_resources));
827 
828   RegistrationData data2;
829   data2.registration_id = 11;
830   data2.scope = URL(origin1, "/bar");
831   data2.script = URL(origin1, "/script2.js");
832   data2.version_id = 101;
833 
834   std::vector<Resource> resources2;
835   resources2.push_back(CreateResource(3, URL(origin1, "/resource3")));
836   resources2.push_back(CreateResource(4, URL(origin1, "/resource4")));
837   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
838             database->WriteRegistration(data2, resources2,
839                                         &newly_purgeable_resources));
840 
841   // |origin2| has one registration.
842   RegistrationData data3;
843   data3.registration_id = 12;
844   data3.scope = URL(origin2, "/hoge");
845   data3.script = URL(origin2, "/script3.js");
846   data3.version_id = 102;
847 
848   std::vector<Resource> resources3;
849   resources3.push_back(CreateResource(5, URL(origin2, "/resource5")));
850   resources3.push_back(CreateResource(6, URL(origin2, "/resource6")));
851   ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
852             database->WriteRegistration(data3, resources3,
853                                         &newly_purgeable_resources));
854 
855   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
856             database->DeleteAllDataForOrigin(origin1,
857                                              &newly_purgeable_resources));
858 
859   // |origin1| should be removed from the unique origin list.
860   std::set<GURL> unique_origins;
861   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
862             database->GetOriginsWithRegistrations(&unique_origins));
863   EXPECT_EQ(1u, unique_origins.size());
864   EXPECT_TRUE(ContainsKey(unique_origins, origin2));
865 
866   // The registrations for |origin1| should be removed.
867   std::vector<RegistrationData> registrations;
868   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
869             database->GetRegistrationsForOrigin(origin1, &registrations));
870   EXPECT_TRUE(registrations.empty());
871 
872   // The registration for |origin2| should not be removed.
873   RegistrationData data_out;
874   std::vector<Resource> resources_out;
875   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration(
876       data3.registration_id, origin2, &data_out, &resources_out));
877   VerifyRegistrationData(data3, data_out);
878   VerifyResourceRecords(resources3, resources_out);
879 
880   // The resources associated with |origin1| should be purgeable.
881   std::set<int64> purgeable_ids_out;
882   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
883             database->GetPurgeableResourceIds(&purgeable_ids_out));
884   EXPECT_EQ(4u, purgeable_ids_out.size());
885   EXPECT_TRUE(ContainsKey(purgeable_ids_out, 1));
886   EXPECT_TRUE(ContainsKey(purgeable_ids_out, 2));
887   EXPECT_TRUE(ContainsKey(purgeable_ids_out, 3));
888   EXPECT_TRUE(ContainsKey(purgeable_ids_out, 4));
889 }
890 
TEST(ServiceWorkerDatabaseTest,DestroyDatabase)891 TEST(ServiceWorkerDatabaseTest, DestroyDatabase) {
892   base::ScopedTempDir database_dir;
893   ASSERT_TRUE(database_dir.CreateUniqueTempDir());
894   scoped_ptr<ServiceWorkerDatabase> database(
895       CreateDatabase(database_dir.path()));
896 
897   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true));
898   ASSERT_TRUE(base::DirectoryExists(database_dir.path()));
899 
900   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->DestroyDatabase());
901   ASSERT_FALSE(base::DirectoryExists(database_dir.path()));
902 }
903 
904 }  // namespace content
905