| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #include <utility> |
| |
| #include "base/location.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "content/browser/fileapi/mock_url_request_delegate.h" |
| #include "content/browser/service_worker/embedded_worker_test_helper.h" |
| #include "content/browser/service_worker/service_worker_context_core.h" |
| #include "content/browser/service_worker/service_worker_context_request_handler.h" |
| #include "content/browser/service_worker/service_worker_disk_cache.h" |
| #include "content/browser/service_worker/service_worker_provider_host.h" |
| #include "content/browser/service_worker/service_worker_registration.h" |
| #include "content/browser/service_worker/service_worker_test_utils.h" |
| #include "content/common/resource_request_body.h" |
| #include "content/common/service_worker/service_worker_utils.h" |
| #include "content/public/test/mock_resource_context.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/net_errors.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/test/url_request/url_request_failed_job.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_job_factory_impl.h" |
| #include "net/url_request/url_request_test_job.h" |
| #include "net/url_request/url_request_test_util.h" |
| #include "storage/browser/blob/blob_storage_context.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| const char kHeaders[] = |
| "HTTP/1.1 200 OK\n" |
| "Content-Type: text/javascript\n" |
| "Expires: Thu, 1 Jan 2100 20:00:00 GMT\n" |
| "\n"; |
| const char kScriptCode[] = "// no script code\n"; |
| |
| void EmptyCallback() { |
| } |
| |
| // The blocksize that ServiceWorkerWriteToCacheJob reads/writes at a time. |
| const int kBlockSize = 16 * 1024; |
| const int kNumBlocks = 8; |
| const int kMiddleBlock = 5; |
| |
| std::string GenerateLongResponse() { |
| return std::string(kNumBlocks * kBlockSize, 'a'); |
| } |
| |
| net::URLRequestJob* CreateNormalURLRequestJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) { |
| return new net::URLRequestTestJob(request, |
| network_delegate, |
| std::string(kHeaders, arraysize(kHeaders)), |
| kScriptCode, |
| true); |
| } |
| |
| net::URLRequestJob* CreateResponseJob(const std::string& response_data, |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) { |
| return new net::URLRequestTestJob(request, network_delegate, |
| std::string(kHeaders, arraysize(kHeaders)), |
| response_data, true); |
| } |
| |
| net::URLRequestJob* CreateFailedURLRequestJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) { |
| return new net::URLRequestFailedJob(request, network_delegate, |
| net::URLRequestFailedJob::START, |
| net::ERR_FAILED); |
| } |
| |
| net::URLRequestJob* CreateInvalidMimeTypeJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) { |
| const char kPlainTextHeaders[] = |
| "HTTP/1.1 200 OK\n" |
| "Content-Type: text/plain\n" |
| "Expires: Thu, 1 Jan 2100 20:00:00 GMT\n" |
| "\n"; |
| return new net::URLRequestTestJob( |
| request, |
| network_delegate, |
| std::string(kPlainTextHeaders, arraysize(kPlainTextHeaders)), |
| kScriptCode, |
| true); |
| } |
| |
| class SSLCertificateErrorJob : public net::URLRequestTestJob { |
| public: |
| SSLCertificateErrorJob(net::URLRequest* request, |
| net::NetworkDelegate* network_delegate, |
| const std::string& response_headers, |
| const std::string& response_data, |
| bool auto_advance) |
| : net::URLRequestTestJob(request, |
| network_delegate, |
| response_headers, |
| response_data, |
| auto_advance), |
| weak_factory_(this) {} |
| void Start() override { |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&SSLCertificateErrorJob::NotifyError, |
| weak_factory_.GetWeakPtr())); |
| } |
| void NotifyError() { |
| net::SSLInfo info; |
| info.cert_status = net::CERT_STATUS_DATE_INVALID; |
| NotifySSLCertificateError(info, true); |
| } |
| |
| protected: |
| ~SSLCertificateErrorJob() override {} |
| base::WeakPtrFactory<SSLCertificateErrorJob> weak_factory_; |
| }; |
| |
| net::URLRequestJob* CreateSSLCertificateErrorJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) { |
| return new SSLCertificateErrorJob(request, |
| network_delegate, |
| std::string(kHeaders, arraysize(kHeaders)), |
| kScriptCode, |
| true); |
| } |
| |
| class CertStatusErrorJob : public net::URLRequestTestJob { |
| public: |
| CertStatusErrorJob(net::URLRequest* request, |
| net::NetworkDelegate* network_delegate, |
| const std::string& response_headers, |
| const std::string& response_data, |
| bool auto_advance) |
| : net::URLRequestTestJob(request, |
| network_delegate, |
| response_headers, |
| response_data, |
| auto_advance) {} |
| void GetResponseInfo(net::HttpResponseInfo* info) override { |
| URLRequestTestJob::GetResponseInfo(info); |
| info->ssl_info.cert_status = net::CERT_STATUS_DATE_INVALID; |
| } |
| |
| protected: |
| ~CertStatusErrorJob() override {} |
| }; |
| |
| net::URLRequestJob* CreateCertStatusErrorJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) { |
| return new CertStatusErrorJob(request, |
| network_delegate, |
| std::string(kHeaders, arraysize(kHeaders)), |
| kScriptCode, |
| true); |
| } |
| |
| class MockHttpProtocolHandler |
| : public net::URLRequestJobFactory::ProtocolHandler { |
| public: |
| typedef base::Callback< |
| net::URLRequestJob*(net::URLRequest*, net::NetworkDelegate*)> JobCallback; |
| |
| explicit MockHttpProtocolHandler(ResourceContext* resource_context) |
| : resource_context_(resource_context) {} |
| ~MockHttpProtocolHandler() override {} |
| |
| net::URLRequestJob* MaybeCreateJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) const override { |
| ServiceWorkerRequestHandler* handler = |
| ServiceWorkerRequestHandler::GetHandler(request); |
| if (handler) { |
| return handler->MaybeCreateJob( |
| request, network_delegate, resource_context_); |
| } |
| return create_job_callback_.Run(request, network_delegate); |
| } |
| void SetCreateJobCallback(const JobCallback& callback) { |
| create_job_callback_ = callback; |
| } |
| |
| private: |
| ResourceContext* resource_context_; |
| JobCallback create_job_callback_; |
| }; |
| |
| class ResponseVerifier : public base::RefCounted<ResponseVerifier> { |
| public: |
| ResponseVerifier(std::unique_ptr<ServiceWorkerResponseReader> reader, |
| const std::string& expected, |
| const base::Callback<void(bool)> callback) |
| : reader_(reader.release()), expected_(expected), callback_(callback) {} |
| |
| void Start() { |
| info_buffer_ = new HttpResponseInfoIOBuffer(); |
| io_buffer_ = new net::IOBuffer(kBlockSize); |
| reader_->ReadInfo(info_buffer_.get(), |
| base::Bind(&ResponseVerifier::OnReadInfoComplete, this)); |
| bytes_read_ = 0; |
| } |
| |
| void OnReadInfoComplete(int result) { |
| if (result < 0) { |
| callback_.Run(false); |
| return; |
| } |
| if (info_buffer_->response_data_size != |
| static_cast<int>(expected_.size())) { |
| callback_.Run(false); |
| return; |
| } |
| ReadSomeData(); |
| } |
| |
| void ReadSomeData() { |
| reader_->ReadData(io_buffer_.get(), kBlockSize, |
| base::Bind(&ResponseVerifier::OnReadDataComplete, this)); |
| } |
| |
| void OnReadDataComplete(int result) { |
| if (result < 0) { |
| callback_.Run(false); |
| return; |
| } |
| if (result == 0) { |
| callback_.Run(true); |
| return; |
| } |
| std::string str(io_buffer_->data(), result); |
| std::string expect = expected_.substr(bytes_read_, result); |
| if (str != expect) { |
| callback_.Run(false); |
| return; |
| } |
| bytes_read_ += result; |
| ReadSomeData(); |
| } |
| |
| private: |
| friend class base::RefCounted<ResponseVerifier>; |
| ~ResponseVerifier() {} |
| |
| std::unique_ptr<ServiceWorkerResponseReader> reader_; |
| const std::string expected_; |
| base::Callback<void(bool)> callback_; |
| scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_; |
| scoped_refptr<net::IOBuffer> io_buffer_; |
| size_t bytes_read_; |
| }; |
| |
| } // namespace |
| |
| class ServiceWorkerWriteToCacheJobTest : public testing::Test { |
| public: |
| ServiceWorkerWriteToCacheJobTest() |
| : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), |
| mock_protocol_handler_(nullptr) {} |
| ~ServiceWorkerWriteToCacheJobTest() override {} |
| |
| void CreateHostForVersion( |
| int process_id, |
| int provider_id, |
| const scoped_refptr<ServiceWorkerVersion>& version) { |
| std::unique_ptr<ServiceWorkerProviderHost> host( |
| new ServiceWorkerProviderHost( |
| process_id, MSG_ROUTING_NONE, provider_id, |
| SERVICE_WORKER_PROVIDER_FOR_WORKER, |
| ServiceWorkerProviderHost::FrameSecurityLevel::SECURE, |
| context()->AsWeakPtr(), nullptr)); |
| base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); |
| context()->AddProviderHost(std::move(host)); |
| provider_host->running_hosted_version_ = version; |
| } |
| |
| void SetUpScriptRequest(int process_id, int provider_id) { |
| request_.reset(); |
| url_request_context_.reset(); |
| url_request_job_factory_.reset(); |
| mock_protocol_handler_ = nullptr; |
| // URLRequestJobs may post clean-up tasks on destruction. |
| base::RunLoop().RunUntilIdle(); |
| |
| url_request_context_.reset(new net::URLRequestContext); |
| mock_protocol_handler_ = new MockHttpProtocolHandler(&resource_context_); |
| url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl); |
| url_request_job_factory_->SetProtocolHandler( |
| "https", base::WrapUnique(mock_protocol_handler_)); |
| url_request_context_->set_job_factory(url_request_job_factory_.get()); |
| |
| request_ = url_request_context_->CreateRequest( |
| script_url_, net::DEFAULT_PRIORITY, &url_request_delegate_); |
| ServiceWorkerRequestHandler::InitializeHandler( |
| request_.get(), context_wrapper(), &blob_storage_context_, process_id, |
| provider_id, false, FETCH_REQUEST_MODE_NO_CORS, |
| FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE, |
| RESOURCE_TYPE_SERVICE_WORKER, REQUEST_CONTEXT_TYPE_SERVICE_WORKER, |
| REQUEST_CONTEXT_FRAME_TYPE_NONE, scoped_refptr<ResourceRequestBody>()); |
| } |
| |
| int NextProviderId() { return next_provider_id_++; } |
| int NextVersionId() { return next_version_id_++; } |
| |
| void SetUp() override { |
| int provider_id = NextProviderId(); |
| helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath())); |
| |
| // A new unstored registration/version. |
| scope_ = GURL("https://host/scope/"); |
| script_url_ = GURL("https://host/script.js"); |
| registration_ = |
| new ServiceWorkerRegistration(scope_, 1L, context()->AsWeakPtr()); |
| version_ = |
| new ServiceWorkerVersion(registration_.get(), script_url_, |
| NextVersionId(), context()->AsWeakPtr()); |
| CreateHostForVersion(helper_->mock_render_process_id(), provider_id, |
| version_); |
| SetUpScriptRequest(helper_->mock_render_process_id(), provider_id); |
| |
| context()->storage()->LazyInitialize(base::Bind(&EmptyCallback)); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void TearDown() override { |
| request_.reset(); |
| url_request_context_.reset(); |
| url_request_job_factory_.reset(); |
| mock_protocol_handler_ = nullptr; |
| version_ = nullptr; |
| registration_ = nullptr; |
| helper_.reset(); |
| // URLRequestJobs may post clean-up tasks on destruction. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| int CreateIncumbent(const std::string& response) { |
| mock_protocol_handler_->SetCreateJobCallback( |
| base::Bind(&CreateResponseJob, response)); |
| request_->Start(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(net::URLRequestStatus::SUCCESS, request_->status().status()); |
| int incumbent_resource_id = |
| version_->script_cache_map()->LookupResourceId(script_url_); |
| EXPECT_NE(kInvalidServiceWorkerResourceId, incumbent_resource_id); |
| |
| registration_->SetActiveVersion(version_); |
| |
| // Teardown the request. |
| request_.reset(); |
| url_request_context_.reset(); |
| url_request_job_factory_.reset(); |
| mock_protocol_handler_ = nullptr; |
| base::RunLoop().RunUntilIdle(); |
| |
| return incumbent_resource_id; |
| } |
| |
| int GetResourceId(ServiceWorkerVersion* version) { |
| return version->script_cache_map()->LookupResourceId(script_url_); |
| } |
| |
| // Performs the net request for an update of |registration_|'s incumbent |
| // to the script |response|. Returns the new version. |
| scoped_refptr<ServiceWorkerVersion> UpdateScript( |
| const std::string& response) { |
| int provider_id = NextProviderId(); |
| scoped_refptr<ServiceWorkerVersion> new_version = |
| new ServiceWorkerVersion(registration_.get(), script_url_, |
| NextVersionId(), context()->AsWeakPtr()); |
| new_version->set_pause_after_download(true); |
| CreateHostForVersion(helper_->mock_render_process_id(), provider_id, |
| new_version); |
| |
| SetUpScriptRequest(helper_->mock_render_process_id(), provider_id); |
| mock_protocol_handler_->SetCreateJobCallback( |
| base::Bind(&CreateResponseJob, response)); |
| request_->Start(); |
| base::RunLoop().RunUntilIdle(); |
| return new_version; |
| } |
| |
| void VerifyResource(int id, const std::string& expected) { |
| ASSERT_NE(kInvalidServiceWorkerResourceId, id); |
| bool is_equal = false; |
| std::unique_ptr<ServiceWorkerResponseReader> reader = |
| context()->storage()->CreateResponseReader(id); |
| scoped_refptr<ResponseVerifier> verifier = new ResponseVerifier( |
| std::move(reader), expected, CreateReceiverOnCurrentThread(&is_equal)); |
| verifier->Start(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(is_equal); |
| } |
| |
| ServiceWorkerContextCore* context() const { return helper_->context(); } |
| ServiceWorkerContextWrapper* context_wrapper() const { |
| return helper_->context_wrapper(); |
| } |
| |
| // Disables the cache to simulate cache errors. |
| void DisableCache() { context()->storage()->disk_cache()->Disable(); } |
| |
| protected: |
| TestBrowserThreadBundle browser_thread_bundle_; |
| std::unique_ptr<EmbeddedWorkerTestHelper> helper_; |
| scoped_refptr<ServiceWorkerRegistration> registration_; |
| scoped_refptr<ServiceWorkerVersion> version_; |
| base::WeakPtr<ServiceWorkerProviderHost> provider_host_; |
| std::unique_ptr<net::URLRequestContext> url_request_context_; |
| std::unique_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_; |
| std::unique_ptr<net::URLRequest> request_; |
| MockHttpProtocolHandler* mock_protocol_handler_; |
| |
| storage::BlobStorageContext blob_storage_context_; |
| content::MockResourceContext resource_context_; |
| |
| MockURLRequestDelegate url_request_delegate_; |
| GURL scope_; |
| GURL script_url_; |
| |
| int next_provider_id_ = 1; |
| int64_t next_version_id_ = 1L; |
| }; |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, Normal) { |
| mock_protocol_handler_->SetCreateJobCallback( |
| base::Bind(&CreateNormalURLRequestJob)); |
| request_->Start(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(net::URLRequestStatus::SUCCESS, request_->status().status()); |
| EXPECT_NE(kInvalidServiceWorkerResourceId, |
| version_->script_cache_map()->LookupResourceId(script_url_)); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, InvalidMimeType) { |
| mock_protocol_handler_->SetCreateJobCallback( |
| base::Bind(&CreateInvalidMimeTypeJob)); |
| request_->Start(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(net::URLRequestStatus::FAILED, request_->status().status()); |
| EXPECT_EQ(net::ERR_INSECURE_RESPONSE, request_->status().error()); |
| EXPECT_EQ(kInvalidServiceWorkerResourceId, |
| version_->script_cache_map()->LookupResourceId(script_url_)); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, SSLCertificateError) { |
| mock_protocol_handler_->SetCreateJobCallback( |
| base::Bind(&CreateSSLCertificateErrorJob)); |
| request_->Start(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(net::URLRequestStatus::FAILED, request_->status().status()); |
| EXPECT_EQ(net::ERR_INSECURE_RESPONSE, request_->status().error()); |
| EXPECT_EQ(kInvalidServiceWorkerResourceId, |
| version_->script_cache_map()->LookupResourceId(script_url_)); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, CertStatusError) { |
| mock_protocol_handler_->SetCreateJobCallback( |
| base::Bind(&CreateCertStatusErrorJob)); |
| request_->Start(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(net::URLRequestStatus::FAILED, request_->status().status()); |
| EXPECT_EQ(net::ERR_INSECURE_RESPONSE, request_->status().error()); |
| EXPECT_EQ(kInvalidServiceWorkerResourceId, |
| version_->script_cache_map()->LookupResourceId(script_url_)); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameScript) { |
| std::string response = GenerateLongResponse(); |
| CreateIncumbent(response); |
| scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response); |
| EXPECT_EQ(kInvalidServiceWorkerResourceId, GetResourceId(version.get())); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameSizeScript) { |
| std::string response = GenerateLongResponse(); |
| CreateIncumbent(response); |
| |
| // Change the first byte. |
| response[0] = 'x'; |
| scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| |
| // Change something within the first block. |
| response[5555] = 'x'; |
| version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| |
| // Change something in a middle block. |
| response[kMiddleBlock * kBlockSize + 111] = 'x'; |
| version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| |
| // Change something within the last block. |
| response[(kNumBlocks - 1) * kBlockSize] = 'x'; |
| version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| |
| // Change the last byte. |
| response[(kNumBlocks * kBlockSize) - 1] = 'x'; |
| version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, Update_TruncatedScript) { |
| std::string response = GenerateLongResponse(); |
| CreateIncumbent(response); |
| |
| // Truncate a single byte. |
| response.resize(response.size() - 1); |
| scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| |
| // Truncate to a middle block. |
| response.resize((kMiddleBlock + 1) * kBlockSize + 111); |
| version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| |
| // Truncate to a block boundary. |
| response.resize((kMiddleBlock - 1) * kBlockSize); |
| version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| |
| // Truncate to a single byte. |
| response.resize(1); |
| version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, Update_ElongatedScript) { |
| std::string original_response = GenerateLongResponse(); |
| CreateIncumbent(original_response); |
| |
| // Extend a single byte. |
| std::string new_response = original_response + 'a'; |
| scoped_refptr<ServiceWorkerVersion> version = UpdateScript(new_response); |
| VerifyResource(GetResourceId(version.get()), new_response); |
| registration_->SetWaitingVersion(version); |
| |
| // Extend multiple blocks. |
| new_response = original_response + std::string(3 * kBlockSize, 'a'); |
| version = UpdateScript(new_response); |
| VerifyResource(GetResourceId(version.get()), new_response); |
| registration_->SetWaitingVersion(version); |
| |
| // Extend multiple blocks and bytes. |
| new_response = original_response + std::string(7 * kBlockSize + 777, 'a'); |
| version = UpdateScript(new_response); |
| VerifyResource(GetResourceId(version.get()), new_response); |
| registration_->SetWaitingVersion(version); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, Update_EmptyScript) { |
| // Create empty incumbent. |
| CreateIncumbent(std::string()); |
| |
| // Update from empty to non-empty. |
| std::string response = GenerateLongResponse(); |
| scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response); |
| VerifyResource(GetResourceId(version.get()), response); |
| registration_->SetWaitingVersion(version); |
| |
| // Update from non-empty to empty. |
| version = UpdateScript(std::string()); |
| VerifyResource(GetResourceId(version.get()), std::string()); |
| registration_->SetWaitingVersion(version); |
| |
| // Update from empty to empty. |
| version = UpdateScript(std::string()); |
| EXPECT_EQ(kInvalidServiceWorkerResourceId, GetResourceId(version.get())); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, Error) { |
| mock_protocol_handler_->SetCreateJobCallback( |
| base::Bind(&CreateFailedURLRequestJob)); |
| request_->Start(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(net::URLRequestStatus::FAILED, request_->status().status()); |
| EXPECT_EQ(net::ERR_FAILED, request_->status().error()); |
| EXPECT_EQ(kInvalidServiceWorkerResourceId, |
| version_->script_cache_map()->LookupResourceId(script_url_)); |
| } |
| |
| TEST_F(ServiceWorkerWriteToCacheJobTest, FailedWriteHeadersToCache) { |
| mock_protocol_handler_->SetCreateJobCallback( |
| base::Bind(&CreateNormalURLRequestJob)); |
| DisableCache(); |
| request_->Start(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(net::URLRequestStatus::FAILED, request_->status().status()); |
| EXPECT_EQ(net::ERR_FAILED, request_->status().error()); |
| } |
| |
| } // namespace content |