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, ®istrations));
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, ®istrations));
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(®istrations));
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(®istrations));
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, ®istrations));
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