| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/service_worker/service_worker_database.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <string> |
| |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/macros.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "content/browser/service_worker/service_worker_database.pb.h" |
| #include "content/common/service_worker/service_worker_types.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
| #include "url/origin.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| typedef ServiceWorkerDatabase::RegistrationData RegistrationData; |
| typedef ServiceWorkerDatabase::ResourceRecord Resource; |
| |
| struct AvailableIds { |
| int64_t reg_id; |
| int64_t res_id; |
| int64_t ver_id; |
| |
| AvailableIds() : reg_id(-1), res_id(-1), ver_id(-1) {} |
| ~AvailableIds() {} |
| }; |
| |
| GURL URL(const GURL& origin, const std::string& path) { |
| EXPECT_TRUE(origin.is_valid()); |
| EXPECT_EQ(origin, origin.GetOrigin()); |
| GURL out(origin.spec() + path); |
| EXPECT_TRUE(out.is_valid()); |
| return out; |
| } |
| |
| Resource CreateResource(int64_t resource_id, |
| const GURL& url, |
| uint64_t size_bytes) { |
| EXPECT_TRUE(url.is_valid()); |
| return Resource(resource_id, url, size_bytes); |
| } |
| |
| ServiceWorkerDatabase* CreateDatabase(const base::FilePath& path) { |
| return new ServiceWorkerDatabase(path); |
| } |
| |
| ServiceWorkerDatabase* CreateDatabaseInMemory() { |
| return new ServiceWorkerDatabase(base::FilePath()); |
| } |
| |
| void VerifyRegistrationData(const RegistrationData& expected, |
| const RegistrationData& actual) { |
| EXPECT_EQ(expected.registration_id, actual.registration_id); |
| EXPECT_EQ(expected.scope, actual.scope); |
| EXPECT_EQ(expected.script, actual.script); |
| EXPECT_EQ(expected.version_id, actual.version_id); |
| EXPECT_EQ(expected.is_active, actual.is_active); |
| EXPECT_EQ(expected.has_fetch_handler, actual.has_fetch_handler); |
| EXPECT_EQ(expected.last_update_check, actual.last_update_check); |
| EXPECT_EQ(expected.resources_total_size_bytes, |
| actual.resources_total_size_bytes); |
| EXPECT_EQ(expected.foreign_fetch_scopes, actual.foreign_fetch_scopes); |
| EXPECT_EQ(expected.foreign_fetch_origins, actual.foreign_fetch_origins); |
| } |
| |
| void VerifyResourceRecords(const std::vector<Resource>& expected, |
| const std::vector<Resource>& actual) { |
| ASSERT_EQ(expected.size(), actual.size()); |
| for (size_t i = 0; i < expected.size(); ++i) { |
| EXPECT_EQ(expected[i].resource_id, actual[i].resource_id); |
| EXPECT_EQ(expected[i].url, actual[i].url); |
| EXPECT_EQ(expected[i].size_bytes, actual[i].size_bytes); |
| } |
| } |
| |
| } // namespace |
| |
| TEST(ServiceWorkerDatabaseTest, OpenDatabase) { |
| base::ScopedTempDir database_dir; |
| ASSERT_TRUE(database_dir.CreateUniqueTempDir()); |
| std::unique_ptr<ServiceWorkerDatabase> database( |
| CreateDatabase(database_dir.path())); |
| |
| // Should be false because the database does not exist at the path. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->LazyOpen(false)); |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); |
| |
| database.reset(CreateDatabase(database_dir.path())); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(false)); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, OpenDatabase_InMemory) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| // Should be false because the database does not exist in memory. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->LazyOpen(false)); |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); |
| database.reset(CreateDatabaseInMemory()); |
| |
| // Should be false because the database is not persistent. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->LazyOpen(false)); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, DatabaseVersion_ValidSchemaVersion) { |
| GURL origin("http://example.com"); |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); |
| |
| // Opening a new database does not write anything, so its schema version |
| // should be 0. |
| int64_t db_version = -1; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadDatabaseVersion(&db_version)); |
| EXPECT_EQ(0u, db_version); |
| |
| // First writing triggers database initialization and bumps the schema |
| // version. |
| std::vector<ServiceWorkerDatabase::ResourceRecord> resources; |
| resources.push_back(CreateResource(1, URL(origin, "/resource"), 10)); |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| ServiceWorkerDatabase::RegistrationData data; |
| data.resources_total_size_bytes = 10; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data, resources, &deleted_version, &newly_purgeable_resources)); |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadDatabaseVersion(&db_version)); |
| EXPECT_LT(0, db_version); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, DatabaseVersion_ObsoleteSchemaVersion) { |
| base::ScopedTempDir database_dir; |
| ASSERT_TRUE(database_dir.CreateUniqueTempDir()); |
| std::unique_ptr<ServiceWorkerDatabase> database( |
| CreateDatabase(database_dir.path())); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); |
| |
| // First writing triggers database initialization and bumps the schema |
| // version. |
| GURL origin("http://example.com"); |
| std::vector<ServiceWorkerDatabase::ResourceRecord> resources; |
| resources.push_back(CreateResource(1, URL(origin, "/resource"), 10)); |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| ServiceWorkerDatabase::RegistrationData data; |
| data.resources_total_size_bytes = 10; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data, resources, &deleted_version, |
| &newly_purgeable_resources)); |
| int64_t db_version = -1; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadDatabaseVersion(&db_version)); |
| ASSERT_LT(0, db_version); |
| |
| // Emulate an obsolete schema version. |
| int64_t old_db_version = 1; |
| leveldb::WriteBatch batch; |
| batch.Put("INITDATA_DB_VERSION", base::Int64ToString(old_db_version)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->WriteBatch(&batch)); |
| db_version = -1; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadDatabaseVersion(&db_version)); |
| ASSERT_EQ(old_db_version, db_version); |
| |
| // Opening the database whose schema version is obsolete should fail. |
| database.reset(CreateDatabase(database_dir.path())); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_FAILED, |
| database->LazyOpen(true)); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, DatabaseVersion_CorruptedSchemaVersion) { |
| base::ScopedTempDir database_dir; |
| ASSERT_TRUE(database_dir.CreateUniqueTempDir()); |
| std::unique_ptr<ServiceWorkerDatabase> database( |
| CreateDatabase(database_dir.path())); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); |
| |
| // First writing triggers database initialization and bumps the schema |
| // version. |
| GURL origin("http://example.com"); |
| std::vector<ServiceWorkerDatabase::ResourceRecord> resources; |
| resources.push_back(CreateResource(1, URL(origin, "/resource"), 10)); |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| ServiceWorkerDatabase::RegistrationData data; |
| data.resources_total_size_bytes = 10; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data, resources, &deleted_version, |
| &newly_purgeable_resources)); |
| int64_t db_version = -1; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadDatabaseVersion(&db_version)); |
| ASSERT_LT(0, db_version); |
| |
| // Emulate a corrupted schema version. |
| int64_t corrupted_db_version = -10; |
| leveldb::WriteBatch batch; |
| batch.Put("INITDATA_DB_VERSION", base::Int64ToString(corrupted_db_version)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->WriteBatch(&batch)); |
| db_version = -1; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED, |
| database->ReadDatabaseVersion(&db_version)); |
| |
| // Opening the database whose schema version is corrupted should fail. |
| database.reset(CreateDatabase(database_dir.path())); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED, |
| database->LazyOpen(true)); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) { |
| base::ScopedTempDir database_dir; |
| ASSERT_TRUE(database_dir.CreateUniqueTempDir()); |
| std::unique_ptr<ServiceWorkerDatabase> database( |
| CreateDatabase(database_dir.path())); |
| |
| GURL origin("http://example.com"); |
| |
| // The database has never been used, so returns initial values. |
| AvailableIds ids; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds( |
| &ids.reg_id, &ids.ver_id, &ids.res_id)); |
| EXPECT_EQ(0, ids.reg_id); |
| EXPECT_EQ(0, ids.ver_id); |
| EXPECT_EQ(0, ids.res_id); |
| |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds( |
| &ids.reg_id, &ids.ver_id, &ids.res_id)); |
| EXPECT_EQ(0, ids.reg_id); |
| EXPECT_EQ(0, ids.ver_id); |
| EXPECT_EQ(0, ids.res_id); |
| |
| // Writing uncommitted resources bumps the next available resource id. |
| const int64_t kUncommittedIds[] = {0, 1, 3, 5, 6, 10}; |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUncommittedResourceIds(std::set<int64_t>( |
| kUncommittedIds, kUncommittedIds + arraysize(kUncommittedIds)))); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->GetNextAvailableIds(&ids.reg_id, &ids.ver_id, &ids.res_id)); |
| EXPECT_EQ(0, ids.reg_id); |
| EXPECT_EQ(0, ids.ver_id); |
| EXPECT_EQ(11, ids.res_id); |
| |
| // Writing purgeable resources bumps the next available id. |
| const int64_t kPurgeableIds[] = {4, 12, 16, 17, 20}; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUncommittedResourceIds(std::set<int64_t>( |
| kPurgeableIds, kPurgeableIds + arraysize(kPurgeableIds)))); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->GetNextAvailableIds(&ids.reg_id, &ids.ver_id, &ids.res_id)); |
| EXPECT_EQ(0, ids.reg_id); |
| EXPECT_EQ(0, ids.ver_id); |
| EXPECT_EQ(21, ids.res_id); |
| |
| // Writing a registration bumps the next available registration and version |
| // ids. |
| std::vector<Resource> resources1; |
| RegistrationData data1; |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| data1.registration_id = 100; |
| data1.scope = URL(origin, "/foo"); |
| data1.script = URL(origin, "/script1.js"); |
| data1.version_id = 200; |
| data1.resources_total_size_bytes = 300; |
| resources1.push_back(CreateResource(1, data1.script, 300)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data1, resources1, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->GetNextAvailableIds(&ids.reg_id, &ids.ver_id, &ids.res_id)); |
| EXPECT_EQ(101, ids.reg_id); |
| EXPECT_EQ(201, ids.ver_id); |
| EXPECT_EQ(21, ids.res_id); |
| |
| // Writing a registration whose ids are lower than the stored ones should not |
| // bump the next available ids. |
| RegistrationData data2; |
| data2.registration_id = 10; |
| data2.scope = URL(origin, "/bar"); |
| data2.script = URL(origin, "/script2.js"); |
| data2.version_id = 20; |
| data2.resources_total_size_bytes = 400; |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(2, data2.script, 400)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data2, resources2, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // Same with resources. |
| int64_t kLowResourceId = 15; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUncommittedResourceIds( |
| std::set<int64_t>(&kLowResourceId, &kLowResourceId + 1))); |
| |
| // Close and reopen the database to verify the stored values. |
| database.reset(CreateDatabase(database_dir.path())); |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds( |
| &ids.reg_id, &ids.ver_id, &ids.res_id)); |
| EXPECT_EQ(101, ids.reg_id); |
| EXPECT_EQ(201, ids.ver_id); |
| EXPECT_EQ(21, ids.res_id); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| std::set<GURL> origins; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithRegistrations(&origins)); |
| EXPECT_TRUE(origins.empty()); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| GURL origin1("http://example.com"); |
| RegistrationData data1; |
| data1.registration_id = 123; |
| data1.scope = URL(origin1, "/foo"); |
| data1.script = URL(origin1, "/script1.js"); |
| data1.version_id = 456; |
| data1.resources_total_size_bytes = 100; |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, data1.script, 100)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data1, resources1, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| GURL origin2("https://www.example.com"); |
| RegistrationData data2; |
| data2.registration_id = 234; |
| data2.scope = URL(origin2, "/bar"); |
| data2.script = URL(origin2, "/script2.js"); |
| data2.version_id = 567; |
| data2.resources_total_size_bytes = 200; |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(2, data2.script, 200)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data2, resources2, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| GURL origin3("https://example.org"); |
| RegistrationData data3; |
| data3.registration_id = 345; |
| data3.scope = URL(origin3, "/hoge"); |
| data3.script = URL(origin3, "/script3.js"); |
| data3.version_id = 678; |
| data3.resources_total_size_bytes = 300; |
| std::vector<Resource> resources3; |
| resources3.push_back(CreateResource(3, data3.script, 300)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data3, resources3, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // |origin3| has two registrations. |
| RegistrationData data4; |
| data4.registration_id = 456; |
| data4.scope = URL(origin3, "/fuga"); |
| data4.script = URL(origin3, "/script4.js"); |
| data4.version_id = 789; |
| data4.resources_total_size_bytes = 400; |
| std::vector<Resource> resources4; |
| resources4.push_back(CreateResource(4, data4.script, 400)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data4, resources4, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| origins.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithRegistrations(&origins)); |
| EXPECT_EQ(3U, origins.size()); |
| EXPECT_TRUE(ContainsKey(origins, origin1)); |
| EXPECT_TRUE(ContainsKey(origins, origin2)); |
| EXPECT_TRUE(ContainsKey(origins, origin3)); |
| |
| // |origin3| has another registration, so should not remove it from the |
| // unique origin list. |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(data4.registration_id, |
| origin3, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data4.registration_id, deleted_version.registration_id); |
| |
| origins.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithRegistrations(&origins)); |
| EXPECT_EQ(3U, origins.size()); |
| EXPECT_TRUE(ContainsKey(origins, origin1)); |
| EXPECT_TRUE(ContainsKey(origins, origin2)); |
| EXPECT_TRUE(ContainsKey(origins, origin3)); |
| |
| // |origin3| should be removed from the unique origin list. |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(data3.registration_id, |
| origin3, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data3.registration_id, deleted_version.registration_id); |
| |
| origins.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithRegistrations(&origins)); |
| EXPECT_EQ(2U, origins.size()); |
| EXPECT_TRUE(ContainsKey(origins, origin1)); |
| EXPECT_TRUE(ContainsKey(origins, origin2)); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, GetRegistrationsForOrigin) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| GURL origin1("http://example.com"); |
| GURL origin2("https://www.example.com"); |
| GURL origin3("https://example.org"); |
| |
| std::vector<RegistrationData> registrations; |
| std::vector<std::vector<Resource>> resources_list; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetRegistrationsForOrigin(origin1, ®istrations, |
| &resources_list)); |
| EXPECT_TRUE(registrations.empty()); |
| EXPECT_TRUE(resources_list.empty()); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| RegistrationData data1; |
| data1.registration_id = 100; |
| data1.scope = URL(origin1, "/foo"); |
| data1.script = URL(origin1, "/script1.js"); |
| data1.version_id = 1000; |
| data1.resources_total_size_bytes = 100; |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, data1.script, 100)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data1, resources1, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| registrations.clear(); |
| resources_list.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetRegistrationsForOrigin(origin1, ®istrations, |
| &resources_list)); |
| EXPECT_EQ(1U, registrations.size()); |
| VerifyRegistrationData(data1, registrations[0]); |
| EXPECT_EQ(1U, resources_list.size()); |
| VerifyResourceRecords(resources1, resources_list[0]); |
| |
| RegistrationData data2; |
| data2.registration_id = 200; |
| data2.scope = URL(origin2, "/bar"); |
| data2.script = URL(origin2, "/script2.js"); |
| data2.version_id = 2000; |
| data2.resources_total_size_bytes = 200; |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(2, data2.script, 200)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data2, resources2, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| registrations.clear(); |
| resources_list.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetRegistrationsForOrigin(origin2, ®istrations, |
| &resources_list)); |
| EXPECT_EQ(1U, registrations.size()); |
| VerifyRegistrationData(data2, registrations[0]); |
| EXPECT_EQ(1U, resources_list.size()); |
| VerifyResourceRecords(resources2, resources_list[0]); |
| |
| RegistrationData data3; |
| data3.registration_id = 300; |
| data3.scope = URL(origin3, "/hoge"); |
| data3.script = URL(origin3, "/script3.js"); |
| data3.version_id = 3000; |
| data3.resources_total_size_bytes = 300; |
| std::vector<Resource> resources3; |
| resources3.push_back(CreateResource(3, data3.script, 300)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data3, resources3, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // |origin3| has two registrations. |
| RegistrationData data4; |
| data4.registration_id = 400; |
| data4.scope = URL(origin3, "/fuga"); |
| data4.script = URL(origin3, "/script4.js"); |
| data4.version_id = 4000; |
| data4.resources_total_size_bytes = 400; |
| std::vector<Resource> resources4; |
| resources4.push_back(CreateResource(4, data4.script, 400)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data4, resources4, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| registrations.clear(); |
| resources_list.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetRegistrationsForOrigin(origin3, ®istrations, |
| &resources_list)); |
| EXPECT_EQ(2U, registrations.size()); |
| VerifyRegistrationData(data3, registrations[0]); |
| VerifyRegistrationData(data4, registrations[1]); |
| EXPECT_EQ(2U, resources_list.size()); |
| VerifyResourceRecords(resources3, resources_list[0]); |
| VerifyResourceRecords(resources4, resources_list[1]); |
| |
| // The third parameter |opt_resources_list| to GetRegistrationsForOrigin() |
| // is optional. So, nullptr should be acceptable. |
| registrations.clear(); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->GetRegistrationsForOrigin(origin1, ®istrations, nullptr)); |
| EXPECT_EQ(1U, registrations.size()); |
| VerifyRegistrationData(data1, registrations[0]); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| std::vector<RegistrationData> registrations; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetAllRegistrations(®istrations)); |
| EXPECT_TRUE(registrations.empty()); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| GURL origin1("http://www1.example.com"); |
| RegistrationData data1; |
| data1.registration_id = 100; |
| data1.scope = URL(origin1, "/foo"); |
| data1.script = URL(origin1, "/script1.js"); |
| data1.version_id = 1000; |
| data1.resources_total_size_bytes = 100; |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, data1.script, 100)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data1, resources1, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| GURL origin2("http://www2.example.com"); |
| RegistrationData data2; |
| data2.registration_id = 200; |
| data2.scope = URL(origin2, "/bar"); |
| data2.script = URL(origin2, "/script2.js"); |
| data2.version_id = 2000; |
| data2.resources_total_size_bytes = 200; |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(2, data2.script, 200)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data2, resources2, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| GURL origin3("http://www3.example.com"); |
| RegistrationData data3; |
| data3.registration_id = 300; |
| data3.scope = URL(origin3, "/hoge"); |
| data3.script = URL(origin3, "/script3.js"); |
| data3.version_id = 3000; |
| data3.resources_total_size_bytes = 300; |
| std::vector<Resource> resources3; |
| resources3.push_back(CreateResource(3, data3.script, 300)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data3, resources3, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // |origin3| has two registrations. |
| RegistrationData data4; |
| data4.registration_id = 400; |
| data4.scope = URL(origin3, "/fuga"); |
| data4.script = URL(origin3, "/script4.js"); |
| data4.version_id = 4000; |
| data4.resources_total_size_bytes = 400; |
| std::vector<Resource> resources4; |
| resources4.push_back(CreateResource(4, data4.script, 400)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data4, resources4, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| registrations.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetAllRegistrations(®istrations)); |
| EXPECT_EQ(4U, registrations.size()); |
| VerifyRegistrationData(data1, registrations[0]); |
| VerifyRegistrationData(data2, registrations[1]); |
| VerifyRegistrationData(data3, registrations[2]); |
| VerifyRegistrationData(data4, registrations[3]); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, Registration_Basic) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| GURL origin("http://example.com"); |
| RegistrationData data; |
| data.registration_id = 100; |
| data.scope = URL(origin, "/foo"); |
| data.script = URL(origin, "/script.js"); |
| data.version_id = 200; |
| data.resources_total_size_bytes = 10939 + 200; |
| data.foreign_fetch_scopes.push_back(URL(origin, "/foo/bar")); |
| |
| std::vector<Resource> resources; |
| resources.push_back(CreateResource(1, URL(origin, "/resource1"), 10939)); |
| resources.push_back(CreateResource(2, URL(origin, "/resource2"), 200)); |
| |
| // Write a resource to the uncommitted list to make sure that writing |
| // registration removes resource ids associated with the registration from |
| // the uncommitted list. |
| std::set<int64_t> uncommitted_ids; |
| uncommitted_ids.insert(resources[0].resource_id); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUncommittedResourceIds(uncommitted_ids)); |
| std::set<int64_t> uncommitted_ids_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetUncommittedResourceIds(&uncommitted_ids_out)); |
| EXPECT_EQ(uncommitted_ids, uncommitted_ids_out); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| deleted_version.version_id = 222; // Dummy initial value |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data, resources, &deleted_version, &newly_purgeable_resources)); |
| EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id); |
| EXPECT_TRUE(newly_purgeable_resources.empty()); |
| |
| // Make sure that the registration and resource records are stored. |
| RegistrationData data_out; |
| std::vector<Resource> resources_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistration( |
| data.registration_id, origin, &data_out, &resources_out)); |
| VerifyRegistrationData(data, data_out); |
| VerifyResourceRecords(resources, resources_out); |
| GURL origin_out; |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistrationOrigin(data.registration_id, &origin_out)); |
| EXPECT_EQ(origin, origin_out); |
| |
| // Make sure that the resource is removed from the uncommitted list. |
| uncommitted_ids_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetUncommittedResourceIds(&uncommitted_ids_out)); |
| EXPECT_TRUE(uncommitted_ids_out.empty()); |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(data.registration_id, |
| origin, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data.version_id, deleted_version.version_id); |
| ASSERT_EQ(resources.size(), newly_purgeable_resources.size()); |
| for (size_t i = 0; i < resources.size(); ++i) |
| EXPECT_EQ(newly_purgeable_resources[i], resources[i].resource_id); |
| |
| // Make sure that the registration and resource records are gone. |
| resources_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistration( |
| data.registration_id, origin, &data_out, &resources_out)); |
| EXPECT_TRUE(resources_out.empty()); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistrationOrigin(data.registration_id, &origin_out)); |
| |
| // Resources should be purgeable because these are no longer referred. |
| std::set<int64_t> purgeable_ids_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetPurgeableResourceIds(&purgeable_ids_out)); |
| EXPECT_EQ(2u, purgeable_ids_out.size()); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources[0].resource_id)); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources[1].resource_id)); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, DeleteNonExistentRegistration) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| GURL origin("http://example.com"); |
| RegistrationData data; |
| data.registration_id = 100; |
| data.scope = URL(origin, "/foo"); |
| data.script = URL(origin, "/script.js"); |
| data.version_id = 200; |
| data.resources_total_size_bytes = 19 + 29129; |
| |
| std::vector<Resource> resources; |
| resources.push_back(CreateResource(1, URL(origin, "/resource1"), 19)); |
| resources.push_back(CreateResource(2, URL(origin, "/resource2"), 29129)); |
| |
| const int64_t kNonExistentRegistrationId = 999; |
| const int64_t kArbitraryVersionId = 222; // Used as a dummy initial value |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| deleted_version.version_id = kArbitraryVersionId; |
| std::vector<int64_t> newly_purgeable_resources; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data, resources, &deleted_version, &newly_purgeable_resources)); |
| EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id); |
| EXPECT_TRUE(newly_purgeable_resources.empty()); |
| |
| // Delete from an origin that has a registration. |
| deleted_version.version_id = kArbitraryVersionId; |
| newly_purgeable_resources.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(kNonExistentRegistrationId, |
| origin, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id); |
| EXPECT_TRUE(newly_purgeable_resources.empty()); |
| |
| // Delete from an origin that has no registration. |
| deleted_version.version_id = kArbitraryVersionId; |
| newly_purgeable_resources.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(kNonExistentRegistrationId, |
| GURL("http://example.net"), |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id); |
| EXPECT_TRUE(newly_purgeable_resources.empty()); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| GURL origin("http://example.com"); |
| RegistrationData data; |
| data.registration_id = 100; |
| data.scope = URL(origin, "/foo"); |
| data.script = URL(origin, "/script.js"); |
| data.version_id = 200; |
| data.resources_total_size_bytes = 10 + 11; |
| data.foreign_fetch_scopes.push_back(URL(origin, "/foo")); |
| data.foreign_fetch_origins.push_back( |
| url::Origin(GURL("https://chromium.org"))); |
| |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, URL(origin, "/resource1"), 10)); |
| resources1.push_back(CreateResource(2, URL(origin, "/resource2"), 11)); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| deleted_version.version_id = 222; // Dummy inital value |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data, resources1, &deleted_version, &newly_purgeable_resources)); |
| EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id); |
| EXPECT_TRUE(newly_purgeable_resources.empty()); |
| |
| // Make sure that the registration and resource records are stored. |
| RegistrationData data_out; |
| std::vector<Resource> resources_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration( |
| data.registration_id, origin, &data_out, &resources_out)); |
| VerifyRegistrationData(data, data_out); |
| VerifyResourceRecords(resources1, resources_out); |
| |
| // Update the registration. |
| RegistrationData updated_data = data; |
| updated_data.version_id = data.version_id + 1; |
| updated_data.resources_total_size_bytes = 12 + 13; |
| updated_data.foreign_fetch_scopes.clear(); |
| updated_data.foreign_fetch_origins.push_back( |
| url::Origin(GURL("https://example.com"))); |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(3, URL(origin, "/resource3"), 12)); |
| resources2.push_back(CreateResource(4, URL(origin, "/resource4"), 13)); |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(updated_data, |
| resources2, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data.version_id, deleted_version.version_id); |
| ASSERT_EQ(resources1.size(), newly_purgeable_resources.size()); |
| for (size_t i = 0; i < resources1.size(); ++i) |
| EXPECT_EQ(newly_purgeable_resources[i], resources1[i].resource_id); |
| |
| // Make sure that |updated_data| is stored and resources referred from |data| |
| // is moved to the purgeable list. |
| resources_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration( |
| updated_data.registration_id, origin, &data_out, &resources_out)); |
| VerifyRegistrationData(updated_data, data_out); |
| VerifyResourceRecords(resources2, resources_out); |
| |
| std::set<int64_t> purgeable_ids_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetPurgeableResourceIds(&purgeable_ids_out)); |
| EXPECT_EQ(2u, purgeable_ids_out.size()); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources1[0].resource_id)); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources1[1].resource_id)); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, Registration_Multiple) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| GURL origin("http://example.com"); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| // Add registration1. |
| RegistrationData data1; |
| data1.registration_id = 100; |
| data1.scope = URL(origin, "/foo"); |
| data1.script = URL(origin, "/script1.js"); |
| data1.version_id = 200; |
| data1.resources_total_size_bytes = 1451 + 15234; |
| |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, URL(origin, "/resource1"), 1451)); |
| resources1.push_back(CreateResource(2, URL(origin, "/resource2"), 15234)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data1, resources1, &deleted_version, &newly_purgeable_resources)); |
| |
| // Add registration2. |
| RegistrationData data2; |
| data2.registration_id = 101; |
| data2.scope = URL(origin, "/bar"); |
| data2.script = URL(origin, "/script2.js"); |
| data2.version_id = 201; |
| data2.resources_total_size_bytes = 5 + 6; |
| |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(3, URL(origin, "/resource3"), 5)); |
| resources2.push_back(CreateResource(4, URL(origin, "/resource4"), 6)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data2, resources2, &deleted_version, &newly_purgeable_resources)); |
| |
| // Make sure that registration1 is stored. |
| RegistrationData data_out; |
| std::vector<Resource> resources_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration( |
| data1.registration_id, origin, &data_out, &resources_out)); |
| VerifyRegistrationData(data1, data_out); |
| VerifyResourceRecords(resources1, resources_out); |
| GURL origin_out; |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistrationOrigin(data1.registration_id, &origin_out)); |
| EXPECT_EQ(origin, origin_out); |
| |
| // Make sure that registration2 is also stored. |
| resources_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration( |
| data2.registration_id, origin, &data_out, &resources_out)); |
| VerifyRegistrationData(data2, data_out); |
| VerifyResourceRecords(resources2, resources_out); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistrationOrigin(data2.registration_id, &origin_out)); |
| EXPECT_EQ(origin, origin_out); |
| |
| std::set<int64_t> purgeable_ids_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetPurgeableResourceIds(&purgeable_ids_out)); |
| EXPECT_TRUE(purgeable_ids_out.empty()); |
| |
| // Delete registration1. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(data1.registration_id, |
| origin, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data1.registration_id, deleted_version.registration_id); |
| |
| // Make sure that registration1 is gone. |
| resources_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistration( |
| data1.registration_id, origin, &data_out, &resources_out)); |
| EXPECT_TRUE(resources_out.empty()); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistrationOrigin(data1.registration_id, &origin_out)); |
| |
| purgeable_ids_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetPurgeableResourceIds(&purgeable_ids_out)); |
| EXPECT_EQ(2u, purgeable_ids_out.size()); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources1[0].resource_id)); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources1[1].resource_id)); |
| |
| // Make sure that registration2 is still alive. |
| resources_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration( |
| data2.registration_id, origin, &data_out, &resources_out)); |
| VerifyRegistrationData(data2, data_out); |
| VerifyResourceRecords(resources2, resources_out); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistrationOrigin(data2.registration_id, &origin_out)); |
| EXPECT_EQ(origin, origin_out); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, Registration_UninitializedDatabase) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| const GURL origin("http://example.com"); |
| |
| // Should be failed because the database does not exist. |
| RegistrationData data_out; |
| std::vector<Resource> resources_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistration( |
| 100, origin, &data_out, &resources_out)); |
| EXPECT_EQ(kInvalidServiceWorkerRegistrationId, data_out.registration_id); |
| EXPECT_TRUE(resources_out.empty()); |
| GURL origin_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistrationOrigin(100, &origin_out)); |
| |
| // Deleting non-existent registration should succeed. |
| RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration( |
| 100, origin, &deleted_version, &newly_purgeable_resources)); |
| EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id); |
| EXPECT_TRUE(newly_purgeable_resources.empty()); |
| |
| // Actually create a new database, but not initialized yet. |
| database->LazyOpen(true); |
| |
| // Should be failed because the database is not initialized. |
| ASSERT_EQ(ServiceWorkerDatabase::UNINITIALIZED, database->state_); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistration( |
| 100, origin, &data_out, &resources_out)); |
| EXPECT_EQ(kInvalidServiceWorkerRegistrationId, data_out.registration_id); |
| EXPECT_TRUE(resources_out.empty()); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistrationOrigin(100, &origin_out)); |
| |
| // Deleting non-existent registration should succeed. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration( |
| 100, origin, &deleted_version, &newly_purgeable_resources)); |
| EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id); |
| EXPECT_TRUE(newly_purgeable_resources.empty()); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, UserData_Basic) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| const GURL kOrigin("http://example.com"); |
| |
| // Add a registration. |
| RegistrationData data; |
| data.registration_id = 100; |
| data.scope = URL(kOrigin, "/foo"); |
| data.script = URL(kOrigin, "/script.js"); |
| data.version_id = 200; |
| data.resources_total_size_bytes = 100; |
| std::vector<Resource> resources; |
| resources.push_back(CreateResource(1, data.script, 100)); |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data, resources, &deleted_version, &newly_purgeable_resources)); |
| |
| // Write user data associated with the stored registration. |
| std::vector<std::string> user_data_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data.registration_id, kOrigin, |
| {{"key1", "data"}})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data.registration_id, {"key1"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data", user_data_out[0]); |
| |
| // Writing user data not associated with the stored registration should be |
| // failed. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->WriteUserData(300, kOrigin, {{"key1", "data"}})); |
| |
| // Write empty user data for a different key. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data.registration_id, kOrigin, |
| {{"key2", std::string()}})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data.registration_id, {"key2"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ(std::string(), user_data_out[0]); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data.registration_id, {"key1"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data", user_data_out[0]); |
| |
| // Overwrite the existing user data. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data.registration_id, kOrigin, |
| {{"key1", "overwrite"}})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data.registration_id, {"key1"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("overwrite", user_data_out[0]); |
| |
| // Delete the user data. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteUserData(data.registration_id, {"key1"})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data.registration_id, {"key1"}, &user_data_out)); |
| EXPECT_TRUE(user_data_out.empty()); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data.registration_id, {"key2"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ(std::string(), user_data_out[0]); |
| |
| // Write/overwrite multiple user data keys. |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData( |
| data.registration_id, kOrigin, |
| {{"key2", "overwrite2"}, {"key3", "data3"}, {"key4", "data4"}})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data.registration_id, {"key1"}, &user_data_out)); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data.registration_id, |
| {"key2", "key3", "key4"}, &user_data_out)); |
| ASSERT_EQ(3u, user_data_out.size()); |
| EXPECT_EQ("overwrite2", user_data_out[0]); |
| EXPECT_EQ("data3", user_data_out[1]); |
| EXPECT_EQ("data4", user_data_out[2]); |
| // Multiple reads fail if one is not found. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data.registration_id, {"key2", "key1"}, |
| &user_data_out)); |
| EXPECT_TRUE(user_data_out.empty()); |
| |
| // Delete multiple user data keys, even if some are not found. |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteUserData(data.registration_id, {"key1", "key2", "key3"})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data.registration_id, {"key1"}, &user_data_out)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data.registration_id, {"key2"}, &user_data_out)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data.registration_id, {"key3"}, &user_data_out)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data.registration_id, {"key4"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data4", user_data_out[0]); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, UserData_DataIsolation) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| const GURL kOrigin("http://example.com"); |
| |
| // Add registration 1. |
| RegistrationData data1; |
| data1.registration_id = 100; |
| data1.scope = URL(kOrigin, "/foo"); |
| data1.script = URL(kOrigin, "/script1.js"); |
| data1.version_id = 200; |
| data1.resources_total_size_bytes = 100; |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, data1.script, 100)); |
| |
| // Add registration 2. |
| RegistrationData data2; |
| data2.registration_id = 101; |
| data2.scope = URL(kOrigin, "/bar"); |
| data2.script = URL(kOrigin, "/script2.js"); |
| data2.version_id = 201; |
| data2.resources_total_size_bytes = 200; |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(2, data2.script, 200)); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data1, resources1, &deleted_version, |
| &newly_purgeable_resources)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data2, resources2, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // Write user data associated with the registration1. |
| std::vector<std::string> user_data_out; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data1.registration_id, kOrigin, |
| {{"key", "data1"}})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data1.registration_id, {"key"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data1", user_data_out[0]); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data2.registration_id, {"key"}, &user_data_out)); |
| |
| // Write user data associated with the registration2. This shouldn't overwrite |
| // the data associated with registration1. |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data2.registration_id, kOrigin, |
| {{"key", "data2"}})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data1.registration_id, {"key"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data1", user_data_out[0]); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data2.registration_id, {"key"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data2", user_data_out[0]); |
| |
| // Get all registrations with user data. |
| std::vector<std::pair<int64_t, std::string>> user_data_list; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserDataForAllRegistrations("key", &user_data_list)); |
| EXPECT_EQ(2u, user_data_list.size()); |
| EXPECT_EQ(data1.registration_id, user_data_list[0].first); |
| EXPECT_EQ("data1", user_data_list[0].second); |
| EXPECT_EQ(data2.registration_id, user_data_list[1].first); |
| EXPECT_EQ("data2", user_data_list[1].second); |
| |
| // Delete the data associated with the registration2. This shouldn't delete |
| // the data associated with registration1. |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteUserData(data2.registration_id, {"key"})); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data1.registration_id, {"key"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data1", user_data_out[0]); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data2.registration_id, {"key"}, &user_data_out)); |
| |
| // And again get all registrations with user data. |
| user_data_list.clear(); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserDataForAllRegistrations("key", &user_data_list)); |
| EXPECT_EQ(1u, user_data_list.size()); |
| EXPECT_EQ(data1.registration_id, user_data_list[0].first); |
| EXPECT_EQ("data1", user_data_list[0].second); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, UserData_DeleteRegistration) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| const GURL kOrigin("http://example.com"); |
| |
| // Add registration 1. |
| RegistrationData data1; |
| data1.registration_id = 100; |
| data1.scope = URL(kOrigin, "/foo"); |
| data1.script = URL(kOrigin, "/script1.js"); |
| data1.version_id = 200; |
| data1.resources_total_size_bytes = 100; |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, data1.script, 100)); |
| |
| // Add registration 2. |
| RegistrationData data2; |
| data2.registration_id = 101; |
| data2.scope = URL(kOrigin, "/bar"); |
| data2.script = URL(kOrigin, "/script2.js"); |
| data2.version_id = 201; |
| data2.resources_total_size_bytes = 200; |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(2, data2.script, 200)); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data1, resources1, &deleted_version, |
| &newly_purgeable_resources)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data2, resources2, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // Write user data associated with the registration1. |
| std::vector<std::string> user_data_out; |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data1.registration_id, kOrigin, |
| {{"key1", "data1"}})); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data1.registration_id, kOrigin, |
| {{"key2", "data2"}})); |
| ASSERT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data1.registration_id, {"key1"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| ASSERT_EQ("data1", user_data_out[0]); |
| ASSERT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data1.registration_id, {"key2"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| ASSERT_EQ("data2", user_data_out[0]); |
| |
| // Write user data associated with the registration2. |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data2.registration_id, kOrigin, |
| {{"key3", "data3"}})); |
| ASSERT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data2.registration_id, {"key3"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| ASSERT_EQ("data3", user_data_out[0]); |
| |
| // Delete all data associated with the registration1. This shouldn't delete |
| // the data associated with registration2. |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration( |
| data1.registration_id, kOrigin, |
| &deleted_version, &newly_purgeable_resources)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data1.registration_id, {"key1"}, &user_data_out)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data1.registration_id, {"key2"}, &user_data_out)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data2.registration_id, {"key3"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data3", user_data_out[0]); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, UserData_UninitializedDatabase) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| const GURL kOrigin("http://example.com"); |
| |
| // Should be failed because the database does not exist. |
| std::vector<std::string> user_data_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(100, {"key"}, &user_data_out)); |
| |
| // Should be failed because the associated registration does not exist. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->WriteUserData(100, kOrigin, {{"key", "data"}})); |
| |
| // Deleting non-existent entry should succeed. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteUserData(100, {"key"})); |
| |
| // Actually create a new database, but not initialized yet. |
| database->LazyOpen(true); |
| |
| // Should be failed because the database is not initialized. |
| ASSERT_EQ(ServiceWorkerDatabase::UNINITIALIZED, database->state_); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(100, {"key"}, &user_data_out)); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->WriteUserData(100, kOrigin, {{"key", "data"}})); |
| |
| // Deleting non-existent entry should succeed. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteUserData(100, {"key"})); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| GURL origin("http://example.com"); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| // Should be false because a registration does not exist. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->UpdateVersionToActive(0, origin)); |
| |
| // Add a registration. |
| RegistrationData data; |
| data.registration_id = 100; |
| data.scope = URL(origin, "/foo"); |
| data.script = URL(origin, "/script.js"); |
| data.version_id = 200; |
| data.is_active = false; |
| data.resources_total_size_bytes = 100; |
| std::vector<Resource> resources; |
| resources.push_back(CreateResource(1, data.script, 100)); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data, resources, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // Make sure that the registration is stored. |
| RegistrationData data_out; |
| std::vector<Resource> resources_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistration( |
| data.registration_id, origin, &data_out, &resources_out)); |
| VerifyRegistrationData(data, data_out); |
| EXPECT_EQ(1u, resources_out.size()); |
| |
| // Activate the registration. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->UpdateVersionToActive(data.registration_id, origin)); |
| |
| // Make sure that the registration is activated. |
| resources_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistration( |
| data.registration_id, origin, &data_out, &resources_out)); |
| RegistrationData expected_data = data; |
| expected_data.is_active = true; |
| VerifyRegistrationData(expected_data, data_out); |
| EXPECT_EQ(1u, resources_out.size()); |
| |
| // Delete the registration. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(data.registration_id, |
| origin, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data.registration_id, deleted_version.registration_id); |
| |
| // Should be false because the registration is gone. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->UpdateVersionToActive(data.registration_id, origin)); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, UpdateLastCheckTime) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| GURL origin("http://example.com"); |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| // Should be false because a registration does not exist. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->UpdateLastCheckTime(0, origin, base::Time::Now())); |
| |
| // Add a registration. |
| RegistrationData data; |
| data.registration_id = 100; |
| data.scope = URL(origin, "/foo"); |
| data.script = URL(origin, "/script.js"); |
| data.version_id = 200; |
| data.last_update_check = base::Time::Now(); |
| data.resources_total_size_bytes = 100; |
| std::vector<Resource> resources; |
| resources.push_back(CreateResource(1, data.script, 100)); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data, resources, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // Make sure that the registration is stored. |
| RegistrationData data_out; |
| std::vector<Resource> resources_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistration( |
| data.registration_id, origin, &data_out, &resources_out)); |
| VerifyRegistrationData(data, data_out); |
| EXPECT_EQ(1u, resources_out.size()); |
| |
| // Update the last check time. |
| base::Time updated_time = base::Time::Now(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->UpdateLastCheckTime( |
| data.registration_id, origin, updated_time)); |
| |
| // Make sure that the registration is updated. |
| resources_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistration( |
| data.registration_id, origin, &data_out, &resources_out)); |
| RegistrationData expected_data = data; |
| expected_data.last_update_check = updated_time; |
| VerifyRegistrationData(expected_data, data_out); |
| EXPECT_EQ(1u, resources_out.size()); |
| |
| // Delete the registration. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(data.registration_id, |
| origin, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data.registration_id, deleted_version.registration_id); |
| |
| // Should be false because the registration is gone. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->UpdateLastCheckTime( |
| data.registration_id, origin, base::Time::Now())); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, UncommittedAndPurgeableResourceIds) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| // Write {1, 2, 3} into the uncommitted list. |
| std::set<int64_t> ids1; |
| ids1.insert(1); |
| ids1.insert(2); |
| ids1.insert(3); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUncommittedResourceIds(ids1)); |
| |
| std::set<int64_t> ids_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetUncommittedResourceIds(&ids_out)); |
| EXPECT_EQ(ids1, ids_out); |
| |
| // Write {2, 4} into the uncommitted list. |
| std::set<int64_t> ids2; |
| ids2.insert(2); |
| ids2.insert(4); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUncommittedResourceIds(ids2)); |
| |
| ids_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetUncommittedResourceIds(&ids_out)); |
| std::set<int64_t> expected = base::STLSetUnion<std::set<int64_t>>(ids1, ids2); |
| EXPECT_EQ(expected, ids_out); |
| |
| // Move {2, 4} from the uncommitted list to the purgeable list. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->PurgeUncommittedResourceIds(ids2)); |
| ids_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetPurgeableResourceIds(&ids_out)); |
| EXPECT_EQ(ids2, ids_out); |
| |
| // Delete {2, 4} from the purgeable list. |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->ClearPurgeableResourceIds(ids2)); |
| ids_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetPurgeableResourceIds(&ids_out)); |
| EXPECT_TRUE(ids_out.empty()); |
| |
| // {1, 3} should be still in the uncommitted list. |
| ids_out.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetUncommittedResourceIds(&ids_out)); |
| expected = base::STLSetDifference<std::set<int64_t>>(ids1, ids2); |
| EXPECT_EQ(expected, ids_out); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| // Data associated with |origin1| will be removed. |
| GURL origin1("http://example.com"); |
| GURL origin2("http://example.org"); |
| |
| // |origin1| has two registrations (registration1 and registration2). |
| RegistrationData data1; |
| data1.registration_id = 10; |
| data1.scope = URL(origin1, "/foo"); |
| data1.script = URL(origin1, "/script1.js"); |
| data1.version_id = 100; |
| data1.resources_total_size_bytes = 2013 + 512; |
| data1.foreign_fetch_scopes.push_back(URL(origin1, "/foo/ff")); |
| |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, URL(origin1, "/resource1"), 2013)); |
| resources1.push_back(CreateResource(2, URL(origin1, "/resource2"), 512)); |
| ASSERT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data1, resources1, &deleted_version, &newly_purgeable_resources)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data1.registration_id, origin1, |
| {{"key1", "data1"}})); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data1.registration_id, origin1, |
| {{"key2", "data2"}})); |
| |
| RegistrationData data2; |
| data2.registration_id = 11; |
| data2.scope = URL(origin1, "/bar"); |
| data2.script = URL(origin1, "/script2.js"); |
| data2.version_id = 101; |
| data2.resources_total_size_bytes = 4 + 5; |
| |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(3, URL(origin1, "/resource3"), 4)); |
| resources2.push_back(CreateResource(4, URL(origin1, "/resource4"), 5)); |
| ASSERT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data2, resources2, &deleted_version, &newly_purgeable_resources)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data2.registration_id, origin1, |
| {{"key3", "data3"}})); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data2.registration_id, origin1, |
| {{"key4", "data4"}})); |
| |
| // |origin2| has one registration (registration3). |
| RegistrationData data3; |
| data3.registration_id = 12; |
| data3.scope = URL(origin2, "/hoge"); |
| data3.script = URL(origin2, "/script3.js"); |
| data3.version_id = 102; |
| data3.resources_total_size_bytes = 6 + 7; |
| data3.foreign_fetch_scopes.push_back(URL(origin2, "/hoge/ff")); |
| |
| std::vector<Resource> resources3; |
| resources3.push_back(CreateResource(5, URL(origin2, "/resource5"), 6)); |
| resources3.push_back(CreateResource(6, URL(origin2, "/resource6"), 7)); |
| ASSERT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration( |
| data3, resources3, &deleted_version, &newly_purgeable_resources)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data3.registration_id, origin2, |
| {{"key5", "data5"}})); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteUserData(data3.registration_id, origin2, |
| {{"key6", "data6"}})); |
| |
| std::set<GURL> origins_to_delete; |
| origins_to_delete.insert(origin1); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteAllDataForOrigins(origins_to_delete, |
| &newly_purgeable_resources)); |
| |
| // |origin1| should be removed from the unique origin list. |
| std::set<GURL> unique_origins; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithRegistrations(&unique_origins)); |
| EXPECT_EQ(1u, unique_origins.size()); |
| EXPECT_TRUE(ContainsKey(unique_origins, origin2)); |
| |
| // |origin1| should be removed from the foreign fetch origin list. |
| unique_origins.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithForeignFetchRegistrations(&unique_origins)); |
| EXPECT_EQ(1u, unique_origins.size()); |
| EXPECT_TRUE(ContainsKey(unique_origins, origin2)); |
| |
| // The registrations for |origin1| should be removed. |
| std::vector<RegistrationData> registrations; |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->GetRegistrationsForOrigin(origin1, ®istrations, nullptr)); |
| EXPECT_TRUE(registrations.empty()); |
| GURL origin_out; |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadRegistrationOrigin(data1.registration_id, &origin_out)); |
| |
| // The registration for |origin2| should not be removed. |
| RegistrationData data_out; |
| std::vector<Resource> resources_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadRegistration( |
| data3.registration_id, origin2, &data_out, &resources_out)); |
| VerifyRegistrationData(data3, data_out); |
| VerifyResourceRecords(resources3, resources_out); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadRegistrationOrigin(data3.registration_id, &origin_out)); |
| EXPECT_EQ(origin2, origin_out); |
| |
| // The resources associated with |origin1| should be purgeable. |
| std::set<int64_t> purgeable_ids_out; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetPurgeableResourceIds(&purgeable_ids_out)); |
| EXPECT_EQ(4u, purgeable_ids_out.size()); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, 1)); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, 2)); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, 3)); |
| EXPECT_TRUE(ContainsKey(purgeable_ids_out, 4)); |
| |
| // The user data associated with |origin1| should be removed. |
| std::vector<std::string> user_data_out; |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data1.registration_id, {"key1"}, &user_data_out)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data1.registration_id, {"key2"}, &user_data_out)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data2.registration_id, {"key3"}, &user_data_out)); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, |
| database->ReadUserData(data2.registration_id, {"key4"}, &user_data_out)); |
| |
| // The user data associated with |origin2| should not be removed. |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data3.registration_id, {"key5"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data5", user_data_out[0]); |
| EXPECT_EQ( |
| ServiceWorkerDatabase::STATUS_OK, |
| database->ReadUserData(data3.registration_id, {"key6"}, &user_data_out)); |
| ASSERT_EQ(1u, user_data_out.size()); |
| EXPECT_EQ("data6", user_data_out[0]); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, DestroyDatabase) { |
| base::ScopedTempDir database_dir; |
| ASSERT_TRUE(database_dir.CreateUniqueTempDir()); |
| std::unique_ptr<ServiceWorkerDatabase> database( |
| CreateDatabase(database_dir.path())); |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); |
| ASSERT_TRUE(base::DirectoryExists(database_dir.path())); |
| |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->DestroyDatabase()); |
| ASSERT_FALSE(base::DirectoryExists(database_dir.path())); |
| } |
| |
| TEST(ServiceWorkerDatabaseTest, GetOriginsWithForeignFetchRegistrations) { |
| std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); |
| |
| std::set<GURL> origins; |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithForeignFetchRegistrations(&origins)); |
| EXPECT_TRUE(origins.empty()); |
| |
| ServiceWorkerDatabase::RegistrationData deleted_version; |
| std::vector<int64_t> newly_purgeable_resources; |
| |
| GURL origin1("http://example.com"); |
| RegistrationData data1; |
| data1.registration_id = 123; |
| data1.scope = URL(origin1, "/foo"); |
| data1.script = URL(origin1, "/script1.js"); |
| data1.version_id = 456; |
| data1.resources_total_size_bytes = 100; |
| data1.foreign_fetch_scopes.push_back(URL(origin1, "/foo/bar")); |
| std::vector<Resource> resources1; |
| resources1.push_back(CreateResource(1, data1.script, 100)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data1, resources1, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| GURL origin2("https://www.example.com"); |
| RegistrationData data2; |
| data2.registration_id = 234; |
| data2.scope = URL(origin2, "/bar"); |
| data2.script = URL(origin2, "/script2.js"); |
| data2.version_id = 567; |
| data2.resources_total_size_bytes = 200; |
| std::vector<Resource> resources2; |
| resources2.push_back(CreateResource(2, data2.script, 200)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data2, resources2, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| GURL origin3("https://example.org"); |
| RegistrationData data3; |
| data3.registration_id = 345; |
| data3.scope = URL(origin3, "/hoge"); |
| data3.script = URL(origin3, "/script3.js"); |
| data3.version_id = 678; |
| data3.resources_total_size_bytes = 300; |
| data3.foreign_fetch_scopes.push_back(URL(origin3, "/hoge/foo")); |
| std::vector<Resource> resources3; |
| resources3.push_back(CreateResource(3, data3.script, 300)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data3, resources3, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| // |origin3| has three registrations. |
| RegistrationData data4; |
| data4.registration_id = 456; |
| data4.scope = URL(origin3, "/fuga"); |
| data4.script = URL(origin3, "/script4.js"); |
| data4.version_id = 789; |
| data4.resources_total_size_bytes = 400; |
| data4.foreign_fetch_scopes.push_back(URL(origin3, "/fuga/bar")); |
| std::vector<Resource> resources4; |
| resources4.push_back(CreateResource(4, data4.script, 400)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data4, resources4, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| RegistrationData data5; |
| data5.registration_id = 567; |
| data5.scope = URL(origin3, "/bla"); |
| data5.script = URL(origin3, "/script5.js"); |
| data5.version_id = 890; |
| data5.resources_total_size_bytes = 500; |
| std::vector<Resource> resources5; |
| resources5.push_back(CreateResource(5, data5.script, 500)); |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(data5, resources5, &deleted_version, |
| &newly_purgeable_resources)); |
| |
| origins.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithForeignFetchRegistrations(&origins)); |
| EXPECT_EQ(2U, origins.size()); |
| EXPECT_TRUE(ContainsKey(origins, origin1)); |
| EXPECT_TRUE(ContainsKey(origins, origin3)); |
| |
| // |origin3| has another registration, so should not remove it from the |
| // foreign fetch origin list. |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(data4.registration_id, origin3, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data4.registration_id, deleted_version.registration_id); |
| |
| origins.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithForeignFetchRegistrations(&origins)); |
| EXPECT_EQ(2U, origins.size()); |
| EXPECT_TRUE(ContainsKey(origins, origin1)); |
| EXPECT_TRUE(ContainsKey(origins, origin3)); |
| |
| // |origin3| should be removed from the foreign fetch origin list, since its |
| // only remaining registration doesn't have foreign fetch scopes. |
| ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->DeleteRegistration(data3.registration_id, origin3, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| EXPECT_EQ(data3.registration_id, deleted_version.registration_id); |
| |
| origins.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithForeignFetchRegistrations(&origins)); |
| EXPECT_EQ(1U, origins.size()); |
| EXPECT_TRUE(ContainsKey(origins, origin1)); |
| |
| // |origin1| should be removed from the foreign fetch origin list, since we |
| // replace its registration with one without scopes. |
| RegistrationData updated_data1 = data1; |
| updated_data1.version_id++; |
| updated_data1.resources_total_size_bytes = 12 + 13; |
| updated_data1.foreign_fetch_scopes.clear(); |
| std::vector<Resource> updated_resources1; |
| updated_resources1.push_back( |
| CreateResource(13, URL(origin1, "/resource3"), 12)); |
| updated_resources1.push_back( |
| CreateResource(14, URL(origin1, "/resource4"), 13)); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->WriteRegistration(updated_data1, updated_resources1, |
| &deleted_version, |
| &newly_purgeable_resources)); |
| |
| origins.clear(); |
| EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| database->GetOriginsWithForeignFetchRegistrations(&origins)); |
| EXPECT_EQ(0U, origins.size()); |
| } |
| |
| } // namespace content |