Home | History | Annotate | Download | only in service_worker
      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