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/bind.h"
      6 #include "base/callback.h"
      7 #include "base/command_line.h"
      8 #include "base/run_loop.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "content/browser/fileapi/chrome_blob_storage_context.h"
     11 #include "content/browser/service_worker/embedded_worker_instance.h"
     12 #include "content/browser/service_worker/embedded_worker_registry.h"
     13 #include "content/browser/service_worker/service_worker_context_core.h"
     14 #include "content/browser/service_worker/service_worker_context_observer.h"
     15 #include "content/browser/service_worker/service_worker_context_wrapper.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_version.h"
     19 #include "content/common/service_worker/service_worker_messages.h"
     20 #include "content/common/service_worker/service_worker_status_code.h"
     21 #include "content/common/service_worker/service_worker_types.h"
     22 #include "content/public/browser/browser_context.h"
     23 #include "content/public/browser/browser_thread.h"
     24 #include "content/public/browser/render_process_host.h"
     25 #include "content/public/browser/storage_partition.h"
     26 #include "content/public/browser/web_contents.h"
     27 #include "content/public/common/content_switches.h"
     28 #include "content/public/test/browser_test_utils.h"
     29 #include "content/public/test/content_browser_test.h"
     30 #include "content/public/test/content_browser_test_utils.h"
     31 #include "content/shell/browser/shell.h"
     32 #include "net/test/embedded_test_server/embedded_test_server.h"
     33 #include "net/test/embedded_test_server/http_request.h"
     34 #include "net/test/embedded_test_server/http_response.h"
     35 #include "net/url_request/url_request_filter.h"
     36 #include "net/url_request/url_request_interceptor.h"
     37 #include "net/url_request/url_request_test_job.h"
     38 #include "storage/browser/blob/blob_data_handle.h"
     39 #include "storage/browser/blob/blob_storage_context.h"
     40 #include "storage/common/blob/blob_data.h"
     41 
     42 namespace content {
     43 
     44 namespace {
     45 
     46 struct FetchResult {
     47   ServiceWorkerStatusCode status;
     48   ServiceWorkerFetchEventResult result;
     49   ServiceWorkerResponse response;
     50   scoped_ptr<storage::BlobDataHandle> blob_data_handle;
     51 };
     52 
     53 void RunAndQuit(const base::Closure& closure,
     54                 const base::Closure& quit,
     55                 base::MessageLoopProxy* original_message_loop) {
     56   closure.Run();
     57   original_message_loop->PostTask(FROM_HERE, quit);
     58 }
     59 
     60 void RunOnIOThread(const base::Closure& closure) {
     61   base::RunLoop run_loop;
     62   BrowserThread::PostTask(
     63       BrowserThread::IO, FROM_HERE,
     64       base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(),
     65                  base::MessageLoopProxy::current()));
     66   run_loop.Run();
     67 }
     68 
     69 void RunOnIOThread(
     70     const base::Callback<void(const base::Closure& continuation)>& closure) {
     71   base::RunLoop run_loop;
     72   base::Closure quit_on_original_thread =
     73       base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
     74                  base::MessageLoopProxy::current().get(),
     75                  FROM_HERE,
     76                  run_loop.QuitClosure());
     77   BrowserThread::PostTask(BrowserThread::IO,
     78                           FROM_HERE,
     79                           base::Bind(closure, quit_on_original_thread));
     80   run_loop.Run();
     81 }
     82 
     83 void ReceivePrepareResult(bool* is_prepared) {
     84   *is_prepared = true;
     85 }
     86 
     87 base::Closure CreatePrepareReceiver(bool* is_prepared) {
     88   return base::Bind(&ReceivePrepareResult, is_prepared);
     89 }
     90 
     91 // Contrary to the style guide, the output parameter of this function comes
     92 // before input parameters so Bind can be used on it to create a FetchCallback
     93 // to pass to DispatchFetchEvent.
     94 void ReceiveFetchResult(BrowserThread::ID run_quit_thread,
     95                         const base::Closure& quit,
     96                         ChromeBlobStorageContext* blob_context,
     97                         FetchResult* out_result,
     98                         ServiceWorkerStatusCode actual_status,
     99                         ServiceWorkerFetchEventResult actual_result,
    100                         const ServiceWorkerResponse& actual_response) {
    101   out_result->status = actual_status;
    102   out_result->result = actual_result;
    103   out_result->response = actual_response;
    104   if (!actual_response.blob_uuid.empty()) {
    105     out_result->blob_data_handle =
    106         blob_context->context()->GetBlobDataFromUUID(
    107             actual_response.blob_uuid);
    108   }
    109   if (!quit.is_null())
    110     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
    111 }
    112 
    113 ServiceWorkerVersion::FetchCallback CreateResponseReceiver(
    114     BrowserThread::ID run_quit_thread,
    115     const base::Closure& quit,
    116     ChromeBlobStorageContext* blob_context,
    117     FetchResult* result) {
    118   return base::Bind(&ReceiveFetchResult, run_quit_thread, quit,
    119                     make_scoped_refptr<ChromeBlobStorageContext>(blob_context),
    120                     result);
    121 }
    122 
    123 void ReadResponseBody(std::string* body,
    124                       storage::BlobDataHandle* blob_data_handle) {
    125   ASSERT_TRUE(blob_data_handle);
    126   ASSERT_EQ(1U, blob_data_handle->data()->items().size());
    127   *body = std::string(blob_data_handle->data()->items()[0].bytes(),
    128                       blob_data_handle->data()->items()[0].length());
    129 }
    130 
    131 void ExpectResultAndRun(bool expected,
    132                         const base::Closure& continuation,
    133                         bool actual) {
    134   EXPECT_EQ(expected, actual);
    135   continuation.Run();
    136 }
    137 
    138 class WorkerActivatedObserver
    139     : public ServiceWorkerContextObserver,
    140       public base::RefCountedThreadSafe<WorkerActivatedObserver> {
    141  public:
    142   explicit WorkerActivatedObserver(ServiceWorkerContextWrapper* context)
    143       : context_(context) {}
    144   void Init() {
    145     RunOnIOThread(base::Bind(&WorkerActivatedObserver::InitOnIOThread, this));
    146   }
    147   // ServiceWorkerContextObserver overrides.
    148   virtual void OnVersionStateChanged(int64 version_id) OVERRIDE {
    149     DCHECK_CURRENTLY_ON(BrowserThread::IO);
    150     const ServiceWorkerVersion* version =
    151         context_->context()->GetLiveVersion(version_id);
    152     if (version->status() == ServiceWorkerVersion::ACTIVATED) {
    153       context_->RemoveObserver(this);
    154       BrowserThread::PostTask(BrowserThread::UI,
    155                               FROM_HERE,
    156                               base::Bind(&WorkerActivatedObserver::Quit, this));
    157     }
    158   }
    159   void Wait() { run_loop_.Run(); }
    160 
    161  private:
    162   friend class base::RefCountedThreadSafe<WorkerActivatedObserver>;
    163   virtual ~WorkerActivatedObserver() {}
    164   void InitOnIOThread() { context_->AddObserver(this); }
    165   void Quit() { run_loop_.Quit(); }
    166 
    167   base::RunLoop run_loop_;
    168   ServiceWorkerContextWrapper* context_;
    169   DISALLOW_COPY_AND_ASSIGN(WorkerActivatedObserver);
    170 };
    171 
    172 scoped_ptr<net::test_server::HttpResponse> VerifyServiceWorkerHeaderInRequest(
    173     const net::test_server::HttpRequest& request) {
    174   EXPECT_EQ(request.relative_url, "/service_worker/generated_sw.js");
    175   std::map<std::string, std::string>::const_iterator it =
    176       request.headers.find("Service-Worker");
    177   EXPECT_TRUE(it != request.headers.end());
    178   EXPECT_EQ("script", it->second);
    179 
    180   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
    181       new net::test_server::BasicHttpResponse());
    182   http_response->set_content_type("text/javascript");
    183   return http_response.PassAs<net::test_server::HttpResponse>();
    184 }
    185 
    186 // The ImportsBustMemcache test requires that the imported script
    187 // would naturally be cached in blink's memcache, but the embedded
    188 // test server doesn't produce headers that allow the blink's memcache
    189 // to do that. This interceptor injects headers that give the import
    190 // an experiration far in the future.
    191 class LongLivedResourceInterceptor : public net::URLRequestInterceptor {
    192  public:
    193   LongLivedResourceInterceptor(const std::string& body)
    194       : body_(body) {}
    195   virtual ~LongLivedResourceInterceptor() {}
    196 
    197   // net::URLRequestInterceptor implementation
    198   virtual net::URLRequestJob* MaybeInterceptRequest(
    199       net::URLRequest* request,
    200       net::NetworkDelegate* network_delegate) const OVERRIDE {
    201     const char kHeaders[] =
    202         "HTTP/1.1 200 OK\0"
    203         "Content-Type: text/javascript\0"
    204         "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
    205         "\0";
    206     std::string headers(kHeaders, arraysize(kHeaders));
    207     return new net::URLRequestTestJob(
    208         request, network_delegate, headers, body_, true);
    209   }
    210 
    211  private:
    212   std::string body_;
    213   DISALLOW_COPY_AND_ASSIGN(LongLivedResourceInterceptor);
    214 };
    215 
    216 void CreateLongLivedResourceInterceptors(
    217     const GURL& worker_url, const GURL& import_url) {
    218   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    219   scoped_ptr<net::URLRequestInterceptor> interceptor;
    220 
    221   interceptor.reset(new LongLivedResourceInterceptor(
    222       "importScripts('long_lived_import.js');"));
    223   net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
    224       worker_url, interceptor.Pass());
    225 
    226   interceptor.reset(new LongLivedResourceInterceptor(
    227       "// the imported script does nothing"));
    228   net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
    229       import_url, interceptor.Pass());
    230 }
    231 
    232 void CountScriptResources(
    233     ServiceWorkerContextWrapper* wrapper,
    234     const GURL& scope,
    235     int* num_resources) {
    236   *num_resources = -1;
    237 
    238   std::vector<ServiceWorkerRegistrationInfo> infos =
    239      wrapper->context()->GetAllLiveRegistrationInfo();
    240   if (infos.empty())
    241     return;
    242 
    243   int version_id;
    244   size_t index = infos.size() - 1;
    245   if (!infos[index].installing_version.is_null)
    246     version_id = infos[index].installing_version.version_id;
    247   else if (!infos[index].waiting_version.is_null)
    248     version_id = infos[1].waiting_version.version_id;
    249   else if (!infos[index].active_version.is_null)
    250     version_id = infos[index].active_version.version_id;
    251   else
    252     return;
    253 
    254   ServiceWorkerVersion* version =
    255       wrapper->context()->GetLiveVersion(version_id);
    256   *num_resources = static_cast<int>(version->script_cache_map()->size());
    257 }
    258 
    259 }  // namespace
    260 
    261 class ServiceWorkerBrowserTest : public ContentBrowserTest {
    262  protected:
    263   typedef ServiceWorkerBrowserTest self;
    264 
    265   virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
    266     command_line->AppendSwitch(
    267         switches::kEnableExperimentalWebPlatformFeatures);
    268   }
    269 
    270   virtual void SetUpOnMainThread() OVERRIDE {
    271     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    272     StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
    273         shell()->web_contents()->GetBrowserContext());
    274     wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
    275         partition->GetServiceWorkerContext());
    276 
    277     // Navigate to the page to set up a renderer page (where we can embed
    278     // a worker).
    279     NavigateToURLBlockUntilNavigationsComplete(
    280         shell(),
    281         embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
    282 
    283     RunOnIOThread(base::Bind(&self::SetUpOnIOThread, this));
    284   }
    285 
    286   virtual void TearDownOnMainThread() OVERRIDE {
    287     RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this));
    288     wrapper_ = NULL;
    289   }
    290 
    291   virtual void SetUpOnIOThread() {}
    292   virtual void TearDownOnIOThread() {}
    293 
    294   ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
    295   ServiceWorkerContext* public_context() { return wrapper(); }
    296 
    297   void AssociateRendererProcessToPattern(const GURL& pattern) {
    298     wrapper_->process_manager()->AddProcessReferenceToPattern(
    299         pattern, shell()->web_contents()->GetRenderProcessHost()->GetID());
    300   }
    301 
    302  private:
    303   scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
    304 };
    305 
    306 class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
    307                                   public EmbeddedWorkerInstance::Listener {
    308  public:
    309   typedef EmbeddedWorkerBrowserTest self;
    310 
    311   EmbeddedWorkerBrowserTest()
    312       : last_worker_status_(EmbeddedWorkerInstance::STOPPED),
    313         pause_mode_(DONT_PAUSE) {}
    314   virtual ~EmbeddedWorkerBrowserTest() {}
    315 
    316   virtual void TearDownOnIOThread() OVERRIDE {
    317     if (worker_) {
    318       worker_->RemoveListener(this);
    319       worker_.reset();
    320     }
    321   }
    322 
    323   void StartOnIOThread() {
    324     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    325     worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
    326     EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
    327     worker_->AddListener(this);
    328 
    329 
    330     const int64 service_worker_version_id = 33L;
    331     const GURL pattern = embedded_test_server()->GetURL("/");
    332     const GURL script_url = embedded_test_server()->GetURL(
    333         "/service_worker/worker.js");
    334     AssociateRendererProcessToPattern(pattern);
    335     int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
    336     wrapper()->process_manager()->AddProcessReferenceToPattern(
    337         pattern, process_id);
    338     worker_->Start(
    339         service_worker_version_id,
    340         pattern,
    341         script_url,
    342         pause_mode_ != DONT_PAUSE,
    343         base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
    344   }
    345   void StartOnIOThread2(ServiceWorkerStatusCode status) {
    346     last_worker_status_ = worker_->status();
    347     EXPECT_EQ(SERVICE_WORKER_OK, status);
    348     EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
    349 
    350     if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
    351       done_closure_.Run();
    352   }
    353 
    354   void StopOnIOThread() {
    355     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    356     EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status());
    357 
    358     ServiceWorkerStatusCode status = worker_->Stop();
    359 
    360     last_worker_status_ = worker_->status();
    361     EXPECT_EQ(SERVICE_WORKER_OK, status);
    362     EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_);
    363 
    364     if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
    365       done_closure_.Run();
    366   }
    367 
    368  protected:
    369   // EmbeddedWorkerInstance::Observer overrides:
    370   virtual void OnStarted() OVERRIDE {
    371     ASSERT_TRUE(worker_ != NULL);
    372     ASSERT_FALSE(done_closure_.is_null());
    373     last_worker_status_ = worker_->status();
    374     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
    375   }
    376   virtual void OnStopped() OVERRIDE {
    377     ASSERT_TRUE(worker_ != NULL);
    378     ASSERT_FALSE(done_closure_.is_null());
    379     last_worker_status_ = worker_->status();
    380     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
    381   }
    382   virtual void OnPausedAfterDownload() OVERRIDE {
    383     if (pause_mode_ == PAUSE_THEN_RESUME)
    384       worker_->ResumeAfterDownload();
    385     else if (pause_mode_ == PAUSE_THEN_STOP)
    386       worker_->Stop();
    387     else
    388       ASSERT_TRUE(false);
    389   }
    390   virtual void OnReportException(const base::string16& error_message,
    391                                  int line_number,
    392                                  int column_number,
    393                                  const GURL& source_url) OVERRIDE {}
    394   virtual void OnReportConsoleMessage(int source_identifier,
    395                                       int message_level,
    396                                       const base::string16& message,
    397                                       int line_number,
    398                                       const GURL& source_url) OVERRIDE {}
    399   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    400     return false;
    401   }
    402 
    403   scoped_ptr<EmbeddedWorkerInstance> worker_;
    404   EmbeddedWorkerInstance::Status last_worker_status_;
    405 
    406   enum {
    407     DONT_PAUSE,
    408     PAUSE_THEN_RESUME,
    409     PAUSE_THEN_STOP,
    410   } pause_mode_;
    411 
    412   // Called by EmbeddedWorkerInstance::Observer overrides so that
    413   // test code can wait for the worker status notifications.
    414   base::Closure done_closure_;
    415 };
    416 
    417 class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
    418  public:
    419   typedef ServiceWorkerVersionBrowserTest self;
    420 
    421   virtual ~ServiceWorkerVersionBrowserTest() {}
    422 
    423   virtual void TearDownOnIOThread() OVERRIDE {
    424     registration_ = NULL;
    425     version_ = NULL;
    426   }
    427 
    428   void InstallTestHelper(const std::string& worker_url,
    429                          ServiceWorkerStatusCode expected_status) {
    430     RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
    431                              worker_url));
    432 
    433     // Dispatch install on a worker.
    434     ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
    435     base::RunLoop install_run_loop;
    436     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    437                             base::Bind(&self::InstallOnIOThread, this,
    438                                        install_run_loop.QuitClosure(),
    439                                        &status));
    440     install_run_loop.Run();
    441     ASSERT_EQ(expected_status, status);
    442 
    443     // Stop the worker.
    444     status = SERVICE_WORKER_ERROR_FAILED;
    445     base::RunLoop stop_run_loop;
    446     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    447                             base::Bind(&self::StopOnIOThread, this,
    448                                        stop_run_loop.QuitClosure(),
    449                                        &status));
    450     stop_run_loop.Run();
    451     ASSERT_EQ(SERVICE_WORKER_OK, status);
    452   }
    453 
    454   void ActivateTestHelper(
    455       const std::string& worker_url,
    456       ServiceWorkerStatusCode expected_status) {
    457     RunOnIOThread(
    458         base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
    459     ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
    460     base::RunLoop run_loop;
    461     BrowserThread::PostTask(
    462         BrowserThread::IO,
    463         FROM_HERE,
    464         base::Bind(
    465             &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status));
    466     run_loop.Run();
    467     ASSERT_EQ(expected_status, status);
    468   }
    469 
    470   void FetchOnRegisteredWorker(
    471       ServiceWorkerFetchEventResult* result,
    472       ServiceWorkerResponse* response,
    473       scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
    474     blob_context_ = ChromeBlobStorageContext::GetFor(
    475         shell()->web_contents()->GetBrowserContext());
    476     bool prepare_result = false;
    477     FetchResult fetch_result;
    478     fetch_result.status = SERVICE_WORKER_ERROR_FAILED;
    479     base::RunLoop fetch_run_loop;
    480     BrowserThread::PostTask(BrowserThread::IO,
    481                             FROM_HERE,
    482                             base::Bind(&self::FetchOnIOThread,
    483                                        this,
    484                                        fetch_run_loop.QuitClosure(),
    485                                        &prepare_result,
    486                                        &fetch_result));
    487     fetch_run_loop.Run();
    488     ASSERT_TRUE(prepare_result);
    489     *result = fetch_result.result;
    490     *response = fetch_result.response;
    491     *blob_data_handle = fetch_result.blob_data_handle.Pass();
    492     ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status);
    493   }
    494 
    495   void FetchTestHelper(const std::string& worker_url,
    496                        ServiceWorkerFetchEventResult* result,
    497                        ServiceWorkerResponse* response,
    498                        scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
    499     RunOnIOThread(
    500         base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
    501     FetchOnRegisteredWorker(result, response, blob_data_handle);
    502   }
    503 
    504   void SetUpRegistrationOnIOThread(const std::string& worker_url) {
    505     const GURL pattern = embedded_test_server()->GetURL("/");
    506     registration_ = new ServiceWorkerRegistration(
    507         pattern,
    508         wrapper()->context()->storage()->NewRegistrationId(),
    509         wrapper()->context()->AsWeakPtr());
    510     version_ = new ServiceWorkerVersion(
    511         registration_.get(),
    512         embedded_test_server()->GetURL(worker_url),
    513         wrapper()->context()->storage()->NewVersionId(),
    514         wrapper()->context()->AsWeakPtr());
    515     AssociateRendererProcessToPattern(pattern);
    516   }
    517 
    518   void StartOnIOThread(const base::Closure& done,
    519                        ServiceWorkerStatusCode* result) {
    520     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    521     version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result));
    522   }
    523 
    524   void InstallOnIOThread(const base::Closure& done,
    525                          ServiceWorkerStatusCode* result) {
    526     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    527     version_->SetStatus(ServiceWorkerVersion::INSTALLING);
    528     version_->DispatchInstallEvent(
    529         -1, CreateReceiver(BrowserThread::UI, done, result));
    530   }
    531 
    532   void ActivateOnIOThread(const base::Closure& done,
    533                           ServiceWorkerStatusCode* result) {
    534     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    535     version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
    536     version_->DispatchActivateEvent(
    537         CreateReceiver(BrowserThread::UI, done, result));
    538   }
    539 
    540   void FetchOnIOThread(const base::Closure& done,
    541                        bool* prepare_result,
    542                        FetchResult* result) {
    543     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    544     ServiceWorkerFetchRequest request(
    545         embedded_test_server()->GetURL("/service_worker/empty.html"),
    546         "GET",
    547         ServiceWorkerHeaderMap(),
    548         GURL(""),
    549         false);
    550     version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
    551     version_->DispatchFetchEvent(
    552         request,
    553         CreatePrepareReceiver(prepare_result),
    554         CreateResponseReceiver(
    555             BrowserThread::UI, done, blob_context_.get(), result));
    556   }
    557 
    558   void StopOnIOThread(const base::Closure& done,
    559                       ServiceWorkerStatusCode* result) {
    560     ASSERT_TRUE(version_.get());
    561     version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
    562   }
    563 
    564   void SyncEventOnIOThread(const base::Closure& done,
    565                            ServiceWorkerStatusCode* result) {
    566     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    567     version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
    568     version_->DispatchSyncEvent(
    569         CreateReceiver(BrowserThread::UI, done, result));
    570   }
    571 
    572  protected:
    573   scoped_refptr<ServiceWorkerRegistration> registration_;
    574   scoped_refptr<ServiceWorkerVersion> version_;
    575   scoped_refptr<ChromeBlobStorageContext> blob_context_;
    576 };
    577 
    578 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
    579   // Start a worker and wait until OnStarted() is called.
    580   base::RunLoop start_run_loop;
    581   done_closure_ = start_run_loop.QuitClosure();
    582   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    583                           base::Bind(&self::StartOnIOThread, this));
    584   start_run_loop.Run();
    585 
    586   ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
    587 
    588   // Stop a worker and wait until OnStopped() is called.
    589   base::RunLoop stop_run_loop;
    590   done_closure_ = stop_run_loop.QuitClosure();
    591   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    592                           base::Bind(&self::StopOnIOThread, this));
    593   stop_run_loop.Run();
    594 
    595   ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
    596 }
    597 
    598 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartPaused_ThenResume) {
    599   pause_mode_ = PAUSE_THEN_RESUME;
    600   base::RunLoop start_run_loop;
    601   done_closure_ = start_run_loop.QuitClosure();
    602   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    603                           base::Bind(&self::StartOnIOThread, this));
    604   start_run_loop.Run();
    605   ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
    606 }
    607 
    608 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
    609                        StartPaused_ThenStop) {
    610   pause_mode_ = PAUSE_THEN_STOP;
    611   base::RunLoop start_run_loop;
    612   done_closure_ = start_run_loop.QuitClosure();
    613   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    614                           base::Bind(&self::StartOnIOThread, this));
    615   start_run_loop.Run();
    616   ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
    617 }
    618 
    619 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
    620   RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
    621                            "/service_worker/worker.js"));
    622 
    623   // Start a worker.
    624   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
    625   base::RunLoop start_run_loop;
    626   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    627                           base::Bind(&self::StartOnIOThread, this,
    628                                      start_run_loop.QuitClosure(),
    629                                      &status));
    630   start_run_loop.Run();
    631   ASSERT_EQ(SERVICE_WORKER_OK, status);
    632 
    633   // Stop the worker.
    634   status = SERVICE_WORKER_ERROR_FAILED;
    635   base::RunLoop stop_run_loop;
    636   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    637                           base::Bind(&self::StopOnIOThread, this,
    638                                      stop_run_loop.QuitClosure(),
    639                                      &status));
    640   stop_run_loop.Run();
    641   ASSERT_EQ(SERVICE_WORKER_OK, status);
    642 }
    643 
    644 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
    645   RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
    646                            "/service_worker/nonexistent.js"));
    647 
    648   // Start a worker for nonexistent URL.
    649   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
    650   base::RunLoop start_run_loop;
    651   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    652                           base::Bind(&self::StartOnIOThread, this,
    653                                      start_run_loop.QuitClosure(),
    654                                      &status));
    655   start_run_loop.Run();
    656   ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
    657 }
    658 
    659 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
    660   InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
    661 }
    662 
    663 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
    664                        InstallWithWaitUntil_Fulfilled) {
    665   InstallTestHelper("/service_worker/worker_install_fulfilled.js",
    666                     SERVICE_WORKER_OK);
    667 }
    668 
    669 // Check that ServiceWorker script requests set a "Service-Worker: script"
    670 // header.
    671 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
    672                        ServiceWorkerScriptHeader) {
    673   embedded_test_server()->RegisterRequestHandler(
    674       base::Bind(&VerifyServiceWorkerHeaderInRequest));
    675   InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
    676 }
    677 
    678 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
    679                        Activate_NoEventListener) {
    680   ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
    681   ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
    682 }
    683 
    684 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
    685   ActivateTestHelper("/service_worker/worker_activate_rejected.js",
    686                      SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
    687 }
    688 
    689 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
    690                        InstallWithWaitUntil_Rejected) {
    691   InstallTestHelper("/service_worker/worker_install_rejected.js",
    692                     SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
    693 }
    694 
    695 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
    696   ServiceWorkerFetchEventResult result;
    697   ServiceWorkerResponse response;
    698   scoped_ptr<storage::BlobDataHandle> blob_data_handle;
    699   FetchTestHelper("/service_worker/fetch_event.js",
    700                   &result, &response, &blob_data_handle);
    701   ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
    702   EXPECT_EQ(301, response.status_code);
    703   EXPECT_EQ("Moved Permanently", response.status_text);
    704   ServiceWorkerHeaderMap expected_headers;
    705   expected_headers["content-language"] = "fi";
    706   expected_headers["content-type"] = "text/html; charset=UTF-8";
    707   EXPECT_EQ(expected_headers, response.headers);
    708 
    709   std::string body;
    710   RunOnIOThread(
    711       base::Bind(&ReadResponseBody,
    712                  &body, base::Owned(blob_data_handle.release())));
    713   EXPECT_EQ("This resource is gone. Gone, gone, gone.", body);
    714 }
    715 
    716 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
    717                        SyncAbortedWithoutFlag) {
    718   RunOnIOThread(base::Bind(
    719       &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
    720 
    721   // Run the sync event.
    722   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
    723   base::RunLoop sync_run_loop;
    724   BrowserThread::PostTask(BrowserThread::IO,
    725                           FROM_HERE,
    726                           base::Bind(&self::SyncEventOnIOThread,
    727                                      this,
    728                                      sync_run_loop.QuitClosure(),
    729                                      &status));
    730   sync_run_loop.Run();
    731   ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
    732 }
    733 
    734 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
    735   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
    736   command_line->AppendSwitch(switches::kEnableServiceWorkerSync);
    737 
    738   RunOnIOThread(base::Bind(
    739       &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
    740   ServiceWorkerFetchEventResult result;
    741   ServiceWorkerResponse response;
    742   scoped_ptr<storage::BlobDataHandle> blob_data_handle;
    743   // Should 404 before sync event.
    744   FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
    745   EXPECT_EQ(404, response.status_code);
    746 
    747   // Run the sync event.
    748   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
    749   base::RunLoop sync_run_loop;
    750   BrowserThread::PostTask(BrowserThread::IO,
    751                           FROM_HERE,
    752                           base::Bind(&self::SyncEventOnIOThread,
    753                                      this,
    754                                      sync_run_loop.QuitClosure(),
    755                                      &status));
    756   sync_run_loop.Run();
    757   ASSERT_EQ(SERVICE_WORKER_OK, status);
    758 
    759   // Should 200 after sync event.
    760   FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
    761   EXPECT_EQ(200, response.status_code);
    762 }
    763 
    764 // ServiceWorkerBrowserTest.Reload is flaky on Android crbug.com/393486
    765 #if defined(OS_ANDROID)
    766 #define MAYBE_Reload DISABLED_Reload
    767 #else
    768 #define MAYBE_Reload Reload
    769 #endif
    770 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, MAYBE_Reload) {
    771   const std::string kPageUrl = "/service_worker/reload.html";
    772   const std::string kWorkerUrl = "/service_worker/fetch_event_reload.js";
    773   {
    774     scoped_refptr<WorkerActivatedObserver> observer =
    775         new WorkerActivatedObserver(wrapper());
    776     observer->Init();
    777     public_context()->RegisterServiceWorker(
    778         embedded_test_server()->GetURL(kPageUrl),
    779         embedded_test_server()->GetURL(kWorkerUrl),
    780         base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
    781     observer->Wait();
    782   }
    783   {
    784     const base::string16 title = base::ASCIIToUTF16("reload=false");
    785     TitleWatcher title_watcher(shell()->web_contents(), title);
    786     NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
    787     EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
    788   }
    789   {
    790     const base::string16 title = base::ASCIIToUTF16("reload=true");
    791     TitleWatcher title_watcher(shell()->web_contents(), title);
    792     ReloadBlockUntilNavigationsComplete(shell(), 1);
    793     EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
    794   }
    795   shell()->Close();
    796   {
    797     base::RunLoop run_loop;
    798     public_context()->UnregisterServiceWorker(
    799         embedded_test_server()->GetURL(kPageUrl),
    800         base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
    801     run_loop.Run();
    802   }
    803 }
    804 
    805 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
    806   const std::string kScopeUrl = "/service_worker/imports_bust_memcache_scope/";
    807   const std::string kPageUrl = "/service_worker/imports_bust_memcache.html";
    808   const std::string kScriptUrl = "/service_worker/worker_with_one_import.js";
    809   const std::string kImportUrl = "/service_worker/long_lived_import.js";
    810   const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
    811   const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
    812 
    813   RunOnIOThread(
    814       base::Bind(&CreateLongLivedResourceInterceptors,
    815                  embedded_test_server()->GetURL(kScriptUrl),
    816                  embedded_test_server()->GetURL(kImportUrl)));
    817 
    818   TitleWatcher title_watcher(shell()->web_contents(), kOKTitle);
    819   title_watcher.AlsoWaitForTitle(kFailTitle);
    820   NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
    821   base::string16 title = title_watcher.WaitAndGetTitle();
    822   EXPECT_EQ(kOKTitle, title);
    823 
    824   // Verify the number of resources in the implicit script cache is correct.
    825   const int kExpectedNumResources = 2;
    826   int num_resources = 0;
    827   RunOnIOThread(
    828       base::Bind(&CountScriptResources,
    829                  base::Unretained(wrapper()),
    830                  embedded_test_server()->GetURL(kScopeUrl),
    831                  &num_resources));
    832   EXPECT_EQ(kExpectedNumResources, num_resources);
    833 }
    834 
    835 class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
    836  public:
    837   typedef ServiceWorkerBlackBoxBrowserTest self;
    838 
    839   void FindRegistrationOnIO(const GURL& document_url,
    840                             ServiceWorkerStatusCode* status,
    841                             const base::Closure& continuation) {
    842     wrapper()->context()->storage()->FindRegistrationForDocument(
    843         document_url,
    844         base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
    845                    this,
    846                    status,
    847                    continuation));
    848   }
    849 
    850   void FindRegistrationOnIO2(
    851       ServiceWorkerStatusCode* out_status,
    852       const base::Closure& continuation,
    853       ServiceWorkerStatusCode status,
    854       const scoped_refptr<ServiceWorkerRegistration>& registration) {
    855     *out_status = status;
    856     if (!registration.get())
    857       EXPECT_NE(SERVICE_WORKER_OK, status);
    858     continuation.Run();
    859   }
    860 };
    861 
    862 static int CountRenderProcessHosts() {
    863   int result = 0;
    864   for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
    865        !iter.IsAtEnd();
    866        iter.Advance()) {
    867     result++;
    868   }
    869   return result;
    870 }
    871 
    872 // Crashes on Android and flakes on CrOS: http://crbug.com/387045
    873 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
    874 #define MAYBE_Registration DISABLED_Registration
    875 #else
    876 #define MAYBE_Registration Registration
    877 #endif
    878 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
    879   // Close the only window to be sure we're not re-using its RenderProcessHost.
    880   shell()->Close();
    881   EXPECT_EQ(0, CountRenderProcessHosts());
    882 
    883   const std::string kWorkerUrl = "/service_worker/fetch_event.js";
    884 
    885   // Unregistering nothing should return false.
    886   {
    887     base::RunLoop run_loop;
    888     public_context()->UnregisterServiceWorker(
    889         embedded_test_server()->GetURL("/"),
    890         base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
    891     run_loop.Run();
    892   }
    893 
    894   // If we use a worker URL that doesn't exist, registration fails.
    895   {
    896     base::RunLoop run_loop;
    897     public_context()->RegisterServiceWorker(
    898         embedded_test_server()->GetURL("/"),
    899         embedded_test_server()->GetURL("/does/not/exist"),
    900         base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
    901     run_loop.Run();
    902   }
    903   EXPECT_EQ(0, CountRenderProcessHosts());
    904 
    905   // Register returns when the promise would be resolved.
    906   {
    907     base::RunLoop run_loop;
    908     public_context()->RegisterServiceWorker(
    909         embedded_test_server()->GetURL("/"),
    910         embedded_test_server()->GetURL(kWorkerUrl),
    911         base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
    912     run_loop.Run();
    913   }
    914   EXPECT_EQ(1, CountRenderProcessHosts());
    915 
    916   // Registering again should succeed, although the algo still
    917   // might not be complete.
    918   {
    919     base::RunLoop run_loop;
    920     public_context()->RegisterServiceWorker(
    921         embedded_test_server()->GetURL("/"),
    922         embedded_test_server()->GetURL(kWorkerUrl),
    923         base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
    924     run_loop.Run();
    925   }
    926 
    927   // The registration algo might not be far enough along to have
    928   // stored the registration data, so it may not be findable
    929   // at this point.
    930 
    931   // Unregistering something should return true.
    932   {
    933     base::RunLoop run_loop;
    934     public_context()->UnregisterServiceWorker(
    935         embedded_test_server()->GetURL("/"),
    936         base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
    937     run_loop.Run();
    938   }
    939   EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
    940                                              "workers eagerly, so their RPHs "
    941                                              "can still be running.";
    942 
    943   // Should not be able to find it.
    944   {
    945     ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
    946     RunOnIOThread(
    947         base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
    948                    this,
    949                    embedded_test_server()->GetURL("/service_worker/empty.html"),
    950                    &status));
    951     EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
    952   }
    953 }
    954 
    955 }  // namespace content
    956