Chromium Code Reviews| Index: content/browser/service_worker/service_worker_storage_unittest.cc |
| diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc |
| index 1e57b5cb5e427dd159456711637bc6e6d73d0f56..206715d7d119c1b66dd5efcf44957413f6c5cc7f 100644 |
| --- a/content/browser/service_worker/service_worker_storage_unittest.cc |
| +++ b/content/browser/service_worker/service_worker_storage_unittest.cc |
| @@ -23,12 +23,17 @@ |
| #include "content/browser/service_worker/service_worker_version.h" |
| #include "content/common/service_worker/service_worker_status_code.h" |
| #include "content/common/service_worker/service_worker_utils.h" |
| +#include "content/public/common/content_client.h" |
| +#include "content/public/common/origin_trial_policy.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "ipc/ipc_message.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/test_completion_callback.h" |
| #include "net/http/http_response_headers.h" |
| +#include "net/http/http_util.h" |
| +#include "net/test/cert_test_util.h" |
| +#include "net/test/test_data_directory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| using net::IOBuffer; |
| @@ -42,6 +47,22 @@ namespace { |
| typedef ServiceWorkerDatabase::RegistrationData RegistrationData; |
| typedef ServiceWorkerDatabase::ResourceRecord ResourceRecord; |
| +// This is a sample public key for testing the API. The corresponding |
| +// private |
|
falken
2016/10/07 03:35:22
nit: line wrapping
horo
2016/10/07 05:33:32
Done.
|
| +// key (use this to generate new samples for this test file) is: |
| +// |
| +// 0x83, 0x67, 0xf4, 0xcd, 0x2a, 0x1f, 0x0e, 0x04, 0x0d, 0x43, 0x13, |
| +// 0x4c, 0x67, 0xc4, 0xf4, 0x28, 0xc9, 0x90, 0x15, 0x02, 0xe2, 0xba, |
| +// 0xfd, 0xbb, 0xfa, 0xbc, 0x92, 0x76, 0x8a, 0x2c, 0x4b, 0xc7, 0x75, |
| +// 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a, |
| +// 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64, |
| +// 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0 |
| +const uint8_t kTestPublicKey[] = { |
| + 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, |
| + 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, |
| + 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0, |
| +}; |
| + |
| void StatusAndQuitCallback(ServiceWorkerStatusCode* result, |
| const base::Closure& quit_closure, |
| ServiceWorkerStatusCode status) { |
| @@ -1762,4 +1783,204 @@ TEST_F(ServiceWorkerStorageDiskTest, OriginHasForeignFetchRegistrations) { |
| EXPECT_FALSE(storage()->OriginHasForeignFetchRegistrations(kOrigin2)); |
| } |
| +class ServiceWorkerStorageOriginTrialsTest : public ServiceWorkerStorageTest { |
| + public: |
| + ServiceWorkerStorageOriginTrialsTest() {} |
| + ~ServiceWorkerStorageOriginTrialsTest() override {} |
| + |
| + protected: |
| + void WriteRegistration(const RegistrationData& registration, |
| + const std::vector<ResourceRecord>& resources) { |
| + ServiceWorkerDatabase::RegistrationData deleted_version; |
| + std::vector<int64_t> newly_purgeable_resources; |
| + |
| + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, |
| + storage()->database_->WriteRegistration( |
| + registration, resources, &deleted_version, |
| + &newly_purgeable_resources)); |
| + } |
| +}; |
| + |
| +TEST_F(ServiceWorkerStorageOriginTrialsTest, AbsentEntryAndEmptyEntry) { |
| + const GURL origin1("http://www1.example.com"); |
| + const GURL scope1("http://www1.example.com/foo/"); |
| + RegistrationData data1; |
| + data1.registration_id = 100; |
| + data1.scope = scope1; |
| + data1.script = GURL(origin1.spec() + "/script.js"); |
| + data1.version_id = 1000; |
| + data1.is_active = true; |
| + data1.resources_total_size_bytes = 100; |
| + // Don't set origin_trial_tokens to simulate old database entry. |
| + std::vector<ServiceWorkerDatabase::ResourceRecord> resources1; |
| + resources1.push_back( |
| + ServiceWorkerDatabase::ResourceRecord(1, data1.script, 100)); |
| + WriteRegistration(data1, resources1); |
| + |
| + const GURL origin2("http://www2.example.com"); |
| + const GURL scope2("http://www2.example.com/foo/"); |
| + RegistrationData data2; |
| + data2.registration_id = 200; |
| + data2.scope = scope2; |
| + data2.script = GURL(origin2.spec() + "/script.js"); |
| + data2.version_id = 2000; |
| + data2.is_active = true; |
| + data2.resources_total_size_bytes = 200; |
| + // Set empty origin_trial_tokens. |
| + data2.origin_trial_tokens = TrialTokenValidator::FeatureToTokensMap(); |
| + std::vector<ServiceWorkerDatabase::ResourceRecord> resources2; |
| + resources2.push_back( |
| + ServiceWorkerDatabase::ResourceRecord(2, data2.script, 200)); |
| + WriteRegistration(data2, resources2); |
| + |
| + scoped_refptr<ServiceWorkerRegistration> found_registration; |
| + |
| + EXPECT_EQ(SERVICE_WORKER_OK, |
| + FindRegistrationForDocument(scope1, &found_registration)); |
| + ASSERT_TRUE(found_registration->active_version()); |
| + // origin_trial_tokens must be unset. |
| + EXPECT_FALSE(found_registration->active_version()->origin_trial_tokens()); |
| + |
| + EXPECT_EQ(SERVICE_WORKER_OK, |
| + FindRegistrationForDocument(scope2, &found_registration)); |
| + ASSERT_TRUE(found_registration->active_version()); |
| + // Empty origin_trial_tokens must exist. |
| + ASSERT_TRUE(found_registration->active_version()->origin_trial_tokens()); |
| + EXPECT_TRUE( |
| + found_registration->active_version()->origin_trial_tokens()->empty()); |
| +} |
| + |
| +class ServiceWorkerStorageOriginTrialsDiskTest |
| + : public ServiceWorkerStorageTest { |
| + public: |
| + ServiceWorkerStorageOriginTrialsDiskTest() { |
| + SetContentClient(&test_content_client_); |
| + } |
| + ~ServiceWorkerStorageOriginTrialsDiskTest() override { |
| + SetContentClient(nullptr); |
| + } |
| + void SetUp() override { |
| + ASSERT_TRUE(InitUserDataDirectory()); |
| + ServiceWorkerStorageTest::SetUp(); |
| + } |
| + |
| + private: |
| + class TestOriginTrialPolicy : public OriginTrialPolicy { |
| + public: |
| + base::StringPiece GetPublicKey() const override { |
| + return base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey), |
| + arraysize(kTestPublicKey)); |
| + } |
| + bool IsFeatureDisabled(base::StringPiece feature) const override { |
| + return false; |
| + } |
| + }; |
| + class TestContentClient : public ContentClient { |
| + public: |
| + // ContentRendererClient methods |
| + OriginTrialPolicy* GetOriginTrialPolicy() override { |
| + return &origin_trial_policy_; |
| + } |
| + |
| + private: |
| + TestOriginTrialPolicy origin_trial_policy_; |
| + }; |
| + TestContentClient test_content_client_; |
| +}; |
| + |
| +TEST_F(ServiceWorkerStorageOriginTrialsDiskTest, FromMainScript) { |
| + LazyInitialize(); |
| + const GURL kScope("https://valid.example.com/scope"); |
| + const GURL kScript("https://valid.example.com/script.js"); |
| + const int64_t kRegistrationId = 1; |
| + const int64_t kVersionId = 1; |
| + scoped_refptr<ServiceWorkerRegistration> registration = |
| + new ServiceWorkerRegistration(kScope, kRegistrationId, |
| + context()->AsWeakPtr()); |
| + scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion( |
| + registration.get(), kScript, kVersionId, context()->AsWeakPtr()); |
| + |
| + net::HttpResponseInfo http_info; |
| + http_info.ssl_info.cert = |
| + net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); |
| + EXPECT_TRUE(http_info.ssl_info.is_valid()); |
| + http_info.ssl_info.security_bits = 0x100; |
| + // SSL3 TLS_DHE_RSA_WITH_AES_256_CBC_SHA |
| + http_info.ssl_info.connection_status = 0x300039; |
| + |
| + const std::string kHTTPHeaderLine("HTTP/1.1 200 OK\n\n"); |
| + const std::string kOriginTrial("Origin-Trial: "); |
| + // Token for Feature1 which expires 2033-05-18. |
| + // generate_token.py valid.example.com Feature1 --expire-timestamp=2000000000 |
| + // TODO(horo): Generate this sample token during the build. |
| + const std::string kFeature1Token( |
| + "AtiUXksymWhTv5ipBE7853JytiYb0RMj3wtEBjqu3PeufQPwV1oEaNjHt4R/oEBfcK0UiWlA" |
| + "P2b9BE2/eThqcAYAAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0" |
| + "NDMiLCAiZmVhdHVyZSI6ICJGZWF0dXJlMSIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ=="); |
| + // Token for Feature2 which expires 2033-05-18. |
| + // generate_token.py valid.example.com Feature2 --expire-timestamp=2000000000 |
| + // TODO(horo): Generate this sample token during the build. |
| + const std::string kFeature2Token1( |
| + "ApmHVC6Dpez0KQNBy13o6cGuoB5AgzOLN0keQMyAN5mjebCwR0MA8/IyjKQIlyom2RuJVg/u" |
| + "LmnqEpldfewkbA8AAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0" |
| + "NDMiLCAiZmVhdHVyZSI6ICJGZWF0dXJlMiIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ=="); |
| + // Token for Feature2 which expires 2036-07-18. |
| + // generate_token.py valid.example.com Feature2 --expire-timestamp=2100000000 |
| + // TODO(horo): Generate this sample token during the build. |
| + const std::string kFeature2Token2( |
| + "AmV2SSxrYstE2zSwZToy7brAbIJakd146apC/6+VDflLmc5yDfJlHGILe5+ZynlcliG7clOR" |
| + "fHhXCzS5Lh1v4AAAAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0" |
| + "NDMiLCAiZmVhdHVyZSI6ICJGZWF0dXJlMiIsICJleHBpcnkiOiAyMTAwMDAwMDAwfQ=="); |
| + // Token for Feature3 which expired 2001-09-09. |
| + // generate_token.py valid.example.com Feature3 --expire-timestamp=1000000000 |
| + const std::string kFeature3ExpiredToken( |
| + "AtSAc03z4qvid34W4MHMxyRFUJKlubZ+P5cs5yg6EiBWcagVbnm5uBgJMJN34pag7D5RywGV" |
| + "ol2RFf+4Sdm1hQ4AAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0" |
| + "NDMiLCAiZmVhdHVyZSI6ICJGZWF0dXJlMyIsICJleHBpcnkiOiAxMDAwMDAwMDAwfQ=="); |
| + http_info.headers = make_scoped_refptr(new net::HttpResponseHeaders("")); |
| + http_info.headers->AddHeader(kOriginTrial + kFeature1Token); |
| + http_info.headers->AddHeader(kOriginTrial + kFeature2Token1); |
| + http_info.headers->AddHeader(kOriginTrial + kFeature2Token2); |
| + http_info.headers->AddHeader(kOriginTrial + kFeature3ExpiredToken); |
| + version->SetMainScriptHttpResponseInfo(http_info); |
| + ASSERT_TRUE(version->origin_trial_tokens()); |
| + const TrialTokenValidator::FeatureToTokensMap& tokens = |
| + *version->origin_trial_tokens(); |
| + ASSERT_EQ(2UL, tokens.size()); |
| + ASSERT_EQ(1UL, tokens.at("Feature1").size()); |
| + EXPECT_EQ(kFeature1Token, tokens.at("Feature1")[0]); |
| + ASSERT_EQ(2UL, tokens.at("Feature2").size()); |
| + EXPECT_EQ(kFeature2Token1, tokens.at("Feature2")[0]); |
| + EXPECT_EQ(kFeature2Token2, tokens.at("Feature2")[1]); |
| + |
| + std::vector<ServiceWorkerDatabase::ResourceRecord> record; |
| + record.push_back(ServiceWorkerDatabase::ResourceRecord(1, kScript, 100)); |
| + version->script_cache_map()->SetResources(record); |
| + version->set_fetch_handler_existence( |
| + ServiceWorkerVersion::FetchHandlerExistence::EXISTS); |
| + version->SetStatus(ServiceWorkerVersion::INSTALLED); |
| + registration->SetActiveVersion(version); |
| + |
| + EXPECT_EQ(SERVICE_WORKER_OK, StoreRegistration(registration, version)); |
| + |
| + // Simulate browser shutdown and restart. |
| + registration = nullptr; |
| + version = nullptr; |
| + InitializeTestHelper(); |
| + LazyInitialize(); |
| + |
| + scoped_refptr<ServiceWorkerRegistration> found_registration; |
| + EXPECT_EQ(SERVICE_WORKER_OK, |
| + FindRegistrationForDocument(kScope, &found_registration)); |
| + ASSERT_TRUE(found_registration->active_version()); |
| + const TrialTokenValidator::FeatureToTokensMap& found_tokens = |
| + *found_registration->active_version()->origin_trial_tokens(); |
| + ASSERT_EQ(2UL, found_tokens.size()); |
| + ASSERT_EQ(1UL, found_tokens.at("Feature1").size()); |
| + EXPECT_EQ(kFeature1Token, found_tokens.at("Feature1")[0]); |
| + ASSERT_EQ(2UL, found_tokens.at("Feature2").size()); |
| + EXPECT_EQ(kFeature2Token1, found_tokens.at("Feature2")[0]); |
| + EXPECT_EQ(kFeature2Token2, found_tokens.at("Feature2")[1]); |
| +} |
| + |
| } // namespace content |