1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/basictypes.h" 6#include "base/callback.h" 7#include "base/memory/scoped_ptr.h" 8#include "base/message_loop/message_loop.h" 9#include "base/run_loop.h" 10#include "content/browser/fileapi/chrome_blob_storage_context.h" 11#include "content/browser/fileapi/mock_url_request_delegate.h" 12#include "content/browser/service_worker/embedded_worker_registry.h" 13#include "content/browser/service_worker/embedded_worker_test_helper.h" 14#include "content/browser/service_worker/service_worker_context_core.h" 15#include "content/browser/service_worker/service_worker_provider_host.h" 16#include "content/browser/service_worker/service_worker_registration.h" 17#include "content/browser/service_worker/service_worker_test_utils.h" 18#include "content/browser/service_worker/service_worker_url_request_job.h" 19#include "content/browser/service_worker/service_worker_version.h" 20#include "content/common/resource_request_body.h" 21#include "content/common/service_worker/service_worker_messages.h" 22#include "content/public/browser/blob_handle.h" 23#include "content/public/test/test_browser_context.h" 24#include "content/public/test/test_browser_thread_bundle.h" 25#include "net/base/io_buffer.h" 26#include "net/http/http_request_headers.h" 27#include "net/http/http_response_headers.h" 28#include "net/url_request/url_request.h" 29#include "net/url_request/url_request_context.h" 30#include "net/url_request/url_request_job_factory_impl.h" 31#include "storage/browser/blob/blob_storage_context.h" 32#include "storage/browser/blob/blob_url_request_job.h" 33#include "storage/browser/blob/blob_url_request_job_factory.h" 34#include "storage/common/blob/blob_data.h" 35#include "testing/gtest/include/gtest/gtest.h" 36 37namespace content { 38 39class ServiceWorkerURLRequestJobTest; 40 41namespace { 42 43const int kProcessID = 1; 44const int kProviderID = 100; 45const char kTestData[] = "Here is sample text for the blob."; 46 47class MockHttpProtocolHandler 48 : public net::URLRequestJobFactory::ProtocolHandler { 49 public: 50 MockHttpProtocolHandler( 51 base::WeakPtr<ServiceWorkerProviderHost> provider_host, 52 base::WeakPtr<storage::BlobStorageContext> blob_storage_context) 53 : provider_host_(provider_host), 54 blob_storage_context_(blob_storage_context) {} 55 virtual ~MockHttpProtocolHandler() {} 56 57 virtual net::URLRequestJob* MaybeCreateJob( 58 net::URLRequest* request, 59 net::NetworkDelegate* network_delegate) const OVERRIDE { 60 ServiceWorkerURLRequestJob* job = 61 new ServiceWorkerURLRequestJob(request, 62 network_delegate, 63 provider_host_, 64 blob_storage_context_, 65 scoped_refptr<ResourceRequestBody>()); 66 job->ForwardToServiceWorker(); 67 return job; 68 } 69 70 private: 71 base::WeakPtr<ServiceWorkerProviderHost> provider_host_; 72 base::WeakPtr<storage::BlobStorageContext> blob_storage_context_; 73}; 74 75// Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns 76// the memory. 77storage::BlobProtocolHandler* CreateMockBlobProtocolHandler( 78 storage::BlobStorageContext* blob_storage_context) { 79 // The FileSystemContext and MessageLoopProxy are not actually used but a 80 // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor. 81 return new storage::BlobProtocolHandler( 82 blob_storage_context, NULL, base::MessageLoopProxy::current().get()); 83} 84 85} // namespace 86 87class ServiceWorkerURLRequestJobTest : public testing::Test { 88 protected: 89 ServiceWorkerURLRequestJobTest() 90 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), 91 blob_data_(new storage::BlobData("blob-id:myblob")) {} 92 virtual ~ServiceWorkerURLRequestJobTest() {} 93 94 virtual void SetUp() OVERRIDE { 95 browser_context_.reset(new TestBrowserContext); 96 SetUpWithHelper(new EmbeddedWorkerTestHelper(kProcessID)); 97 } 98 99 void SetUpWithHelper(EmbeddedWorkerTestHelper* helper) { 100 helper_.reset(helper); 101 102 registration_ = new ServiceWorkerRegistration( 103 GURL("http://example.com/"), 104 1L, 105 helper_->context()->AsWeakPtr()); 106 version_ = new ServiceWorkerVersion( 107 registration_.get(), 108 GURL("http://example.com/service_worker.js"), 109 1L, 110 helper_->context()->AsWeakPtr()); 111 112 scoped_ptr<ServiceWorkerProviderHost> provider_host( 113 new ServiceWorkerProviderHost( 114 kProcessID, kProviderID, helper_->context()->AsWeakPtr(), NULL)); 115 provider_host->AssociateRegistration(registration_.get()); 116 registration_->SetActiveVersion(version_.get()); 117 118 ChromeBlobStorageContext* chrome_blob_storage_context = 119 ChromeBlobStorageContext::GetFor(browser_context_.get()); 120 // Wait for chrome_blob_storage_context to finish initializing. 121 base::RunLoop().RunUntilIdle(); 122 storage::BlobStorageContext* blob_storage_context = 123 chrome_blob_storage_context->context(); 124 125 url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl); 126 url_request_job_factory_->SetProtocolHandler( 127 "http", 128 new MockHttpProtocolHandler(provider_host->AsWeakPtr(), 129 blob_storage_context->AsWeakPtr())); 130 url_request_job_factory_->SetProtocolHandler( 131 "blob", CreateMockBlobProtocolHandler(blob_storage_context)); 132 url_request_context_.set_job_factory(url_request_job_factory_.get()); 133 134 helper_->context()->AddProviderHost(provider_host.Pass()); 135 } 136 137 virtual void TearDown() OVERRIDE { 138 version_ = NULL; 139 registration_ = NULL; 140 helper_.reset(); 141 } 142 143 void TestRequest(int expected_status_code, 144 const std::string& expected_status_text, 145 const std::string& expected_response) { 146 request_ = url_request_context_.CreateRequest( 147 GURL("http://example.com/foo.html"), 148 net::DEFAULT_PRIORITY, 149 &url_request_delegate_, 150 NULL); 151 152 request_->set_method("GET"); 153 request_->Start(); 154 base::RunLoop().RunUntilIdle(); 155 EXPECT_TRUE(request_->status().is_success()); 156 EXPECT_EQ(expected_status_code, 157 request_->response_headers()->response_code()); 158 EXPECT_EQ(expected_status_text, 159 request_->response_headers()->GetStatusText()); 160 EXPECT_EQ(expected_response, url_request_delegate_.response_data()); 161 } 162 163 TestBrowserThreadBundle thread_bundle_; 164 165 scoped_ptr<TestBrowserContext> browser_context_; 166 scoped_ptr<EmbeddedWorkerTestHelper> helper_; 167 scoped_refptr<ServiceWorkerRegistration> registration_; 168 scoped_refptr<ServiceWorkerVersion> version_; 169 170 scoped_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_; 171 net::URLRequestContext url_request_context_; 172 MockURLRequestDelegate url_request_delegate_; 173 scoped_ptr<net::URLRequest> request_; 174 175 scoped_refptr<storage::BlobData> blob_data_; 176 177 private: 178 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLRequestJobTest); 179}; 180 181TEST_F(ServiceWorkerURLRequestJobTest, Simple) { 182 version_->SetStatus(ServiceWorkerVersion::ACTIVATED); 183 TestRequest(200, "OK", std::string()); 184} 185 186// Responds to fetch events with a blob. 187class BlobResponder : public EmbeddedWorkerTestHelper { 188 public: 189 BlobResponder(int mock_render_process_id, const std::string& blob_uuid) 190 : EmbeddedWorkerTestHelper(mock_render_process_id), 191 blob_uuid_(blob_uuid) {} 192 virtual ~BlobResponder() {} 193 194 protected: 195 virtual void OnFetchEvent(int embedded_worker_id, 196 int request_id, 197 const ServiceWorkerFetchRequest& request) OVERRIDE { 198 SimulateSend(new ServiceWorkerHostMsg_FetchEventFinished( 199 embedded_worker_id, 200 request_id, 201 SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, 202 ServiceWorkerResponse( 203 GURL(""), 200, "OK", ServiceWorkerHeaderMap(), blob_uuid_))); 204 } 205 206 std::string blob_uuid_; 207 208 private: 209 DISALLOW_COPY_AND_ASSIGN(BlobResponder); 210}; 211 212TEST_F(ServiceWorkerURLRequestJobTest, BlobResponse) { 213 ChromeBlobStorageContext* blob_storage_context = 214 ChromeBlobStorageContext::GetFor(browser_context_.get()); 215 std::string expected_response; 216 for (int i = 0; i < 1024; ++i) { 217 blob_data_->AppendData(kTestData); 218 expected_response += kTestData; 219 } 220 scoped_ptr<storage::BlobDataHandle> blob_handle = 221 blob_storage_context->context()->AddFinishedBlob(blob_data_.get()); 222 SetUpWithHelper(new BlobResponder(kProcessID, blob_handle->uuid())); 223 224 version_->SetStatus(ServiceWorkerVersion::ACTIVATED); 225 TestRequest(200, "OK", expected_response); 226} 227 228TEST_F(ServiceWorkerURLRequestJobTest, NonExistentBlobUUIDResponse) { 229 SetUpWithHelper(new BlobResponder(kProcessID, "blob-id:nothing-is-here")); 230 version_->SetStatus(ServiceWorkerVersion::ACTIVATED); 231 TestRequest(500, "Service Worker Response Error", std::string()); 232} 233 234// TODO(kinuko): Add more tests with different response data and also for 235// FallbackToNetwork case. 236 237} // namespace content 238