service_worker_url_request_job_unittest.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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
36namespace content {
37
38class ServiceWorkerURLRequestJobTest;
39
40namespace {
41
42const int kProcessID = 1;
43const int kProviderID = 100;
44const char kTestData[] = "Here is sample text for the blob.";
45
46class 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.
72webkit_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
82class 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 private:
170  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLRequestJobTest);
171};
172
173TEST_F(ServiceWorkerURLRequestJobTest, Simple) {
174  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
175  TestRequest(200, "OK", std::string());
176}
177
178// Responds to fetch events with a blob.
179class BlobResponder : public EmbeddedWorkerTestHelper {
180 public:
181  BlobResponder(int mock_render_process_id, const std::string& blob_uuid)
182      : EmbeddedWorkerTestHelper(mock_render_process_id),
183        blob_uuid_(blob_uuid) {}
184  virtual ~BlobResponder() {}
185
186 protected:
187  virtual void OnFetchEvent(int embedded_worker_id,
188                            int request_id,
189                            const ServiceWorkerFetchRequest& request) OVERRIDE {
190    SimulateSend(new ServiceWorkerHostMsg_FetchEventFinished(
191        embedded_worker_id,
192        request_id,
193        SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
194        ServiceWorkerResponse(GURL(""),
195                              200,
196                              "OK",
197                              std::map<std::string, std::string>(),
198                              blob_uuid_)));
199  }
200
201  std::string blob_uuid_;
202
203 private:
204  DISALLOW_COPY_AND_ASSIGN(BlobResponder);
205};
206
207TEST_F(ServiceWorkerURLRequestJobTest, BlobResponse) {
208  ChromeBlobStorageContext* blob_storage_context =
209      ChromeBlobStorageContext::GetFor(browser_context_.get());
210  std::string expected_response;
211  for (int i = 0; i < 1024; ++i) {
212    blob_data_->AppendData(kTestData);
213    expected_response += kTestData;
214  }
215  scoped_ptr<webkit_blob::BlobDataHandle> blob_handle =
216      blob_storage_context->context()->AddFinishedBlob(blob_data_);
217  SetUpWithHelper(new BlobResponder(kProcessID, blob_handle->uuid()));
218
219  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
220  TestRequest(200, "OK", expected_response);
221}
222
223TEST_F(ServiceWorkerURLRequestJobTest, NonExistentBlobUUIDResponse) {
224  SetUpWithHelper(new BlobResponder(kProcessID, "blob-id:nothing-is-here"));
225  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
226  TestRequest(500, "Service Worker Response Error", std::string());
227}
228
229// TODO(kinuko): Add more tests with different response data and also for
230// FallbackToNetwork case.
231
232}  // namespace content
233