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