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