Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_browsertest.cc
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 "content/browser/fileapi/chrome_blob_storage_context.h"
10 #include "content/browser/service_worker/embedded_worker_instance.h"
11 #include "content/browser/service_worker/embedded_worker_registry.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_context_wrapper.h"
14 #include "content/browser/service_worker/service_worker_registration.h"
15 #include "content/browser/service_worker/service_worker_test_utils.h"
16 #include "content/browser/service_worker/service_worker_version.h"
17 #include "content/common/service_worker/service_worker_messages.h"
18 #include "content/common/service_worker/service_worker_status_code.h"
19 #include "content/common/service_worker/service_worker_types.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/test/content_browser_test.h"
27 #include "content/public/test/content_browser_test_utils.h"
28 #include "content/shell/browser/shell.h"
29 #include "net/test/embedded_test_server/embedded_test_server.h"
30 #include "webkit/browser/blob/blob_data_handle.h"
31 #include "webkit/browser/blob/blob_storage_context.h"
32 #include "webkit/common/blob/blob_data.h"
33
34 namespace content {
35
36 namespace {
37
38 struct FetchResult {
39   ServiceWorkerStatusCode status;
40   ServiceWorkerFetchEventResult result;
41   ServiceWorkerResponse response;
42   scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
43 };
44
45 void RunAndQuit(const base::Closure& closure,
46                 const base::Closure& quit,
47                 base::MessageLoopProxy* original_message_loop) {
48   closure.Run();
49   original_message_loop->PostTask(FROM_HERE, quit);
50 }
51
52 void RunOnIOThread(const base::Closure& closure) {
53   base::RunLoop run_loop;
54   BrowserThread::PostTask(
55       BrowserThread::IO, FROM_HERE,
56       base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(),
57                  base::MessageLoopProxy::current()));
58   run_loop.Run();
59 }
60
61 void RunOnIOThread(
62     const base::Callback<void(const base::Closure& continuation)>& closure) {
63   base::RunLoop run_loop;
64   base::Closure quit_on_original_thread =
65       base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
66                  base::MessageLoopProxy::current().get(),
67                  FROM_HERE,
68                  run_loop.QuitClosure());
69   BrowserThread::PostTask(BrowserThread::IO,
70                           FROM_HERE,
71                           base::Bind(closure, quit_on_original_thread));
72   run_loop.Run();
73 }
74
75 // Contrary to the style guide, the output parameter of this function comes
76 // before input parameters so Bind can be used on it to create a FetchCallback
77 // to pass to DispatchFetchEvent.
78 void ReceiveFetchResult(BrowserThread::ID run_quit_thread,
79                         const base::Closure& quit,
80                         ChromeBlobStorageContext* blob_context,
81                         FetchResult* out_result,
82                         ServiceWorkerStatusCode actual_status,
83                         ServiceWorkerFetchEventResult actual_result,
84                         const ServiceWorkerResponse& actual_response) {
85   out_result->status = actual_status;
86   out_result->result = actual_result;
87   out_result->response = actual_response;
88   if (!actual_response.blob_uuid.empty()) {
89     out_result->blob_data_handle =
90         blob_context->context()->GetBlobDataFromUUID(
91             actual_response.blob_uuid);
92   }
93   if (!quit.is_null())
94     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
95 }
96
97 ServiceWorkerVersion::FetchCallback CreateResponseReceiver(
98     BrowserThread::ID run_quit_thread,
99     const base::Closure& quit,
100     ChromeBlobStorageContext* blob_context,
101     FetchResult* result) {
102   return base::Bind(&ReceiveFetchResult, run_quit_thread, quit,
103                     make_scoped_refptr<ChromeBlobStorageContext>(blob_context),
104                     result);
105 }
106
107 void ReadResponseBody(std::string* body,
108                       webkit_blob::BlobDataHandle* blob_data_handle) {
109   ASSERT_TRUE(blob_data_handle);
110   ASSERT_EQ(1U, blob_data_handle->data()->items().size());
111   *body = std::string(blob_data_handle->data()->items()[0].bytes(),
112                       blob_data_handle->data()->items()[0].length());
113 }
114
115 }  // namespace
116
117 class ServiceWorkerBrowserTest : public ContentBrowserTest {
118  protected:
119   typedef ServiceWorkerBrowserTest self;
120
121   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
122     command_line->AppendSwitch(switches::kEnableServiceWorker);
123   }
124
125   virtual void SetUpOnMainThread() OVERRIDE {
126     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
127     StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
128         shell()->web_contents()->GetBrowserContext());
129     wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
130         partition->GetServiceWorkerContext());
131
132     // Navigate to the page to set up a renderer page (where we can embed
133     // a worker).
134     NavigateToURLBlockUntilNavigationsComplete(
135         shell(),
136         embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
137
138     RunOnIOThread(base::Bind(&self::SetUpOnIOThread, this));
139   }
140
141   virtual void TearDownOnMainThread() OVERRIDE {
142     RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this));
143     wrapper_ = NULL;
144   }
145
146   virtual void SetUpOnIOThread() {}
147   virtual void TearDownOnIOThread() {}
148
149   ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
150   ServiceWorkerContext* public_context() { return wrapper(); }
151
152   void AssociateRendererProcessToWorker(EmbeddedWorkerInstance* worker) {
153     worker->AddProcessReference(
154         shell()->web_contents()->GetRenderProcessHost()->GetID());
155   }
156
157  private:
158   scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
159 };
160
161 class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
162                                   public EmbeddedWorkerInstance::Listener {
163  public:
164   typedef EmbeddedWorkerBrowserTest self;
165
166   EmbeddedWorkerBrowserTest()
167       : last_worker_status_(EmbeddedWorkerInstance::STOPPED) {}
168   virtual ~EmbeddedWorkerBrowserTest() {}
169
170   virtual void TearDownOnIOThread() OVERRIDE {
171     if (worker_) {
172       worker_->RemoveListener(this);
173       worker_.reset();
174     }
175   }
176
177   void StartOnIOThread() {
178     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
179     worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
180     EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
181     worker_->AddListener(this);
182
183     AssociateRendererProcessToWorker(worker_.get());
184
185     const int64 service_worker_version_id = 33L;
186     const GURL scope = embedded_test_server()->GetURL("/*");
187     const GURL script_url = embedded_test_server()->GetURL(
188         "/service_worker/worker.js");
189     std::vector<int> processes;
190     processes.push_back(
191         shell()->web_contents()->GetRenderProcessHost()->GetID());
192     worker_->Start(
193         service_worker_version_id,
194         scope,
195         script_url,
196         processes,
197         base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
198   }
199   void StartOnIOThread2(ServiceWorkerStatusCode status) {
200     last_worker_status_ = worker_->status();
201     EXPECT_EQ(SERVICE_WORKER_OK, status);
202     EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
203
204     if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
205       done_closure_.Run();
206   }
207
208   void StopOnIOThread() {
209     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
210     EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status());
211
212     ServiceWorkerStatusCode status = worker_->Stop();
213
214     last_worker_status_ = worker_->status();
215     EXPECT_EQ(SERVICE_WORKER_OK, status);
216     EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_);
217
218     if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
219       done_closure_.Run();
220   }
221
222  protected:
223   // EmbeddedWorkerInstance::Observer overrides:
224   virtual void OnStarted() OVERRIDE {
225     ASSERT_TRUE(worker_ != NULL);
226     ASSERT_FALSE(done_closure_.is_null());
227     last_worker_status_ = worker_->status();
228     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
229   }
230   virtual void OnStopped() OVERRIDE {
231     ASSERT_TRUE(worker_ != NULL);
232     ASSERT_FALSE(done_closure_.is_null());
233     last_worker_status_ = worker_->status();
234     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
235   }
236   virtual void OnReportException(const base::string16& error_message,
237                                  int line_number,
238                                  int column_number,
239                                  const GURL& source_url) OVERRIDE {}
240   virtual void OnReportConsoleMessage(int source_identifier,
241                                       int message_level,
242                                       const base::string16& message,
243                                       int line_number,
244                                       const GURL& source_url) OVERRIDE {}
245   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
246     return false;
247   }
248
249   scoped_ptr<EmbeddedWorkerInstance> worker_;
250   EmbeddedWorkerInstance::Status last_worker_status_;
251
252   // Called by EmbeddedWorkerInstance::Observer overrides so that
253   // test code can wait for the worker status notifications.
254   base::Closure done_closure_;
255 };
256
257 class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
258  public:
259   typedef ServiceWorkerVersionBrowserTest self;
260
261   virtual ~ServiceWorkerVersionBrowserTest() {}
262
263   virtual void TearDownOnIOThread() OVERRIDE {
264     registration_ = NULL;
265     version_ = NULL;
266   }
267
268   void InstallTestHelper(const std::string& worker_url,
269                          ServiceWorkerStatusCode expected_status) {
270     RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
271                              worker_url));
272
273     // Dispatch install on a worker.
274     ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
275     base::RunLoop install_run_loop;
276     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
277                             base::Bind(&self::InstallOnIOThread, this,
278                                        install_run_loop.QuitClosure(),
279                                        &status));
280     install_run_loop.Run();
281     ASSERT_EQ(expected_status, status);
282
283     // Stop the worker.
284     status = SERVICE_WORKER_ERROR_FAILED;
285     base::RunLoop stop_run_loop;
286     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
287                             base::Bind(&self::StopOnIOThread, this,
288                                        stop_run_loop.QuitClosure(),
289                                        &status));
290     stop_run_loop.Run();
291     ASSERT_EQ(SERVICE_WORKER_OK, status);
292   }
293
294   void ActivateTestHelper(
295       const std::string& worker_url,
296       ServiceWorkerStatusCode expected_status) {
297     RunOnIOThread(
298         base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
299     version_->SetStatus(ServiceWorkerVersion::INSTALLED);
300     ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
301     base::RunLoop run_loop;
302     BrowserThread::PostTask(
303         BrowserThread::IO,
304         FROM_HERE,
305         base::Bind(
306             &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status));
307     run_loop.Run();
308     ASSERT_EQ(expected_status, status);
309   }
310
311   void FetchOnRegisteredWorker(
312       ServiceWorkerFetchEventResult* result,
313       ServiceWorkerResponse* response,
314       scoped_ptr<webkit_blob::BlobDataHandle>* blob_data_handle) {
315     blob_context_ = ChromeBlobStorageContext::GetFor(
316         shell()->web_contents()->GetBrowserContext());
317     FetchResult fetch_result;
318     fetch_result.status = SERVICE_WORKER_ERROR_FAILED;
319     base::RunLoop fetch_run_loop;
320     BrowserThread::PostTask(BrowserThread::IO,
321                             FROM_HERE,
322                             base::Bind(&self::FetchOnIOThread,
323                                        this,
324                                        fetch_run_loop.QuitClosure(),
325                                        &fetch_result));
326     fetch_run_loop.Run();
327     *result = fetch_result.result;
328     *response = fetch_result.response;
329     *blob_data_handle = fetch_result.blob_data_handle.Pass();
330     ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status);
331   }
332
333   void FetchTestHelper(
334       const std::string& worker_url,
335       ServiceWorkerFetchEventResult* result,
336       ServiceWorkerResponse* response,
337       scoped_ptr<webkit_blob::BlobDataHandle>* blob_data_handle) {
338     RunOnIOThread(
339         base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
340     FetchOnRegisteredWorker(result, response, blob_data_handle);
341   }
342
343   void SetUpRegistrationOnIOThread(const std::string& worker_url) {
344     registration_ = new ServiceWorkerRegistration(
345         embedded_test_server()->GetURL("/*"),
346         embedded_test_server()->GetURL(worker_url),
347         wrapper()->context()->storage()->NewRegistrationId(),
348         wrapper()->context()->AsWeakPtr());
349     version_ = new ServiceWorkerVersion(
350         registration_,
351         wrapper()->context()->storage()->NewVersionId(),
352         wrapper()->context()->AsWeakPtr());
353     AssociateRendererProcessToWorker(version_->embedded_worker());
354   }
355
356   void StartOnIOThread(const base::Closure& done,
357                        ServiceWorkerStatusCode* result) {
358     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
359     version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result));
360   }
361
362   void InstallOnIOThread(const base::Closure& done,
363                          ServiceWorkerStatusCode* result) {
364     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
365     version_->DispatchInstallEvent(
366         -1, CreateReceiver(BrowserThread::UI, done, result));
367   }
368
369   void ActivateOnIOThread(const base::Closure& done,
370                           ServiceWorkerStatusCode* result) {
371     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
372     version_->SetStatus(ServiceWorkerVersion::INSTALLED);
373     version_->DispatchActivateEvent(
374         CreateReceiver(BrowserThread::UI, done, result));
375   }
376
377   void FetchOnIOThread(const base::Closure& done, FetchResult* result) {
378     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
379     ServiceWorkerFetchRequest request(
380         embedded_test_server()->GetURL("/service_worker/empty.html"),
381         "GET",
382         std::map<std::string, std::string>());
383     version_->SetStatus(ServiceWorkerVersion::ACTIVE);
384     version_->DispatchFetchEvent(
385         request, CreateResponseReceiver(BrowserThread::UI, done,
386                                         blob_context_, result));
387   }
388
389   void StopOnIOThread(const base::Closure& done,
390                       ServiceWorkerStatusCode* result) {
391     ASSERT_TRUE(version_);
392     version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
393   }
394
395   void SyncEventOnIOThread(const base::Closure& done,
396                            ServiceWorkerStatusCode* result) {
397     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
398     version_->SetStatus(ServiceWorkerVersion::ACTIVE);
399     version_->DispatchSyncEvent(
400         CreateReceiver(BrowserThread::UI, done, result));
401   }
402
403  protected:
404   scoped_refptr<ServiceWorkerRegistration> registration_;
405   scoped_refptr<ServiceWorkerVersion> version_;
406   scoped_refptr<ChromeBlobStorageContext> blob_context_;
407 };
408
409 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
410   // Start a worker and wait until OnStarted() is called.
411   base::RunLoop start_run_loop;
412   done_closure_ = start_run_loop.QuitClosure();
413   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
414                           base::Bind(&self::StartOnIOThread, this));
415   start_run_loop.Run();
416
417   ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
418
419   // Stop a worker and wait until OnStopped() is called.
420   base::RunLoop stop_run_loop;
421   done_closure_ = stop_run_loop.QuitClosure();
422   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
423                           base::Bind(&self::StopOnIOThread, this));
424   stop_run_loop.Run();
425
426   ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
427 }
428
429 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
430   RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
431                            "/service_worker/worker.js"));
432
433   // Start a worker.
434   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
435   base::RunLoop start_run_loop;
436   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
437                           base::Bind(&self::StartOnIOThread, this,
438                                      start_run_loop.QuitClosure(),
439                                      &status));
440   start_run_loop.Run();
441   ASSERT_EQ(SERVICE_WORKER_OK, 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 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
455   RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
456                            "/service_worker/nonexistent.js"));
457
458   // Start a worker for nonexistent URL.
459   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
460   base::RunLoop start_run_loop;
461   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
462                           base::Bind(&self::StartOnIOThread, this,
463                                      start_run_loop.QuitClosure(),
464                                      &status));
465   start_run_loop.Run();
466   ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
467 }
468
469 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
470   InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
471 }
472
473 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
474                        InstallWithWaitUntil_Fulfilled) {
475   InstallTestHelper("/service_worker/worker_install_fulfilled.js",
476                     SERVICE_WORKER_OK);
477 }
478
479 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
480                        Activate_NoEventListener) {
481   ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
482   ASSERT_EQ(ServiceWorkerVersion::ACTIVE, version_->status());
483 }
484
485 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
486   ActivateTestHelper("/service_worker/worker_activate_rejected.js",
487                      SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
488 }
489
490 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
491                        InstallWithWaitUntil_Rejected) {
492   InstallTestHelper("/service_worker/worker_install_rejected.js",
493                     SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
494 }
495
496 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
497   ServiceWorkerFetchEventResult result;
498   ServiceWorkerResponse response;
499   scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
500   FetchTestHelper("/service_worker/fetch_event.js",
501                   &result, &response, &blob_data_handle);
502   ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
503   EXPECT_EQ(301, response.status_code);
504   EXPECT_EQ("Moved Permanently", response.status_text);
505   std::map<std::string, std::string> expected_headers;
506   expected_headers["Content-Language"] = "fi";
507   expected_headers["Content-Type"] = "text/html; charset=UTF-8";
508   EXPECT_EQ(expected_headers, response.headers);
509
510   std::string body;
511   RunOnIOThread(
512       base::Bind(&ReadResponseBody,
513                  &body, base::Owned(blob_data_handle.release())));
514   EXPECT_EQ("This resource is gone. Gone, gone, gone.", body);
515 }
516
517 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
518                        SyncAbortedWithoutFlag) {
519   RunOnIOThread(base::Bind(
520       &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
521
522   // Run the sync event.
523   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
524   base::RunLoop sync_run_loop;
525   BrowserThread::PostTask(BrowserThread::IO,
526                           FROM_HERE,
527                           base::Bind(&self::SyncEventOnIOThread,
528                                      this,
529                                      sync_run_loop.QuitClosure(),
530                                      &status));
531   sync_run_loop.Run();
532   ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
533 }
534
535 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
536   CommandLine* command_line = CommandLine::ForCurrentProcess();
537   command_line->AppendSwitch(switches::kEnableServiceWorkerSync);
538
539   RunOnIOThread(base::Bind(
540       &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
541   ServiceWorkerFetchEventResult result;
542   ServiceWorkerResponse response;
543   scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
544   // Should 404 before sync event.
545   FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
546   EXPECT_EQ(404, response.status_code);
547
548   // Run the sync event.
549   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
550   base::RunLoop sync_run_loop;
551   BrowserThread::PostTask(BrowserThread::IO,
552                           FROM_HERE,
553                           base::Bind(&self::SyncEventOnIOThread,
554                                      this,
555                                      sync_run_loop.QuitClosure(),
556                                      &status));
557   sync_run_loop.Run();
558   ASSERT_EQ(SERVICE_WORKER_OK, status);
559
560   // Should 200 after sync event.
561   FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
562   EXPECT_EQ(200, response.status_code);
563 }
564
565 class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
566  public:
567   typedef ServiceWorkerBlackBoxBrowserTest self;
568
569   static void ExpectResultAndRun(bool expected,
570                                  const base::Closure& continuation,
571                                  bool actual) {
572     EXPECT_EQ(expected, actual);
573     continuation.Run();
574   }
575
576   void FindRegistrationOnIO(const GURL& document_url,
577                             ServiceWorkerStatusCode* status,
578                             GURL* script_url,
579                             const base::Closure& continuation) {
580     wrapper()->context()->storage()->FindRegistrationForDocument(
581         document_url,
582         base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
583                    this,
584                    status,
585                    script_url,
586                    continuation));
587   }
588
589   void FindRegistrationOnIO2(
590       ServiceWorkerStatusCode* out_status,
591       GURL* script_url,
592       const base::Closure& continuation,
593       ServiceWorkerStatusCode status,
594       const scoped_refptr<ServiceWorkerRegistration>& registration) {
595     *out_status = status;
596     if (registration) {
597       *script_url = registration->script_url();
598     } else {
599       EXPECT_NE(SERVICE_WORKER_OK, status);
600     }
601     continuation.Run();
602   }
603 };
604
605 static int CountRenderProcessHosts() {
606   int result = 0;
607   for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
608        !iter.IsAtEnd();
609        iter.Advance()) {
610     result++;
611   }
612   return result;
613 }
614
615 // Crashes on Android: http://crbug.com/387045
616 #if defined(OS_ANDROID)
617 #define MAYBE_Registration DISABLED_Registration
618 #else
619 #define MAYBE_Registration Registration
620 #endif
621 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
622   // Close the only window to be sure we're not re-using its RenderProcessHost.
623   shell()->Close();
624   EXPECT_EQ(0, CountRenderProcessHosts());
625
626   const std::string kWorkerUrl = "/service_worker/fetch_event.js";
627
628   // Unregistering nothing should return true.
629   {
630     base::RunLoop run_loop;
631     public_context()->UnregisterServiceWorker(
632         embedded_test_server()->GetURL("/*"),
633         base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
634                    true,
635                    run_loop.QuitClosure()));
636     run_loop.Run();
637   }
638
639   // If we use a worker URL that doesn't exist, registration fails.
640   {
641     base::RunLoop run_loop;
642     public_context()->RegisterServiceWorker(
643         embedded_test_server()->GetURL("/*"),
644         embedded_test_server()->GetURL("/does/not/exist"),
645         base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
646                    false,
647                    run_loop.QuitClosure()));
648     run_loop.Run();
649   }
650   EXPECT_EQ(0, CountRenderProcessHosts());
651
652   // Register returns when the promise would be resolved.
653   {
654     base::RunLoop run_loop;
655     public_context()->RegisterServiceWorker(
656         embedded_test_server()->GetURL("/*"),
657         embedded_test_server()->GetURL(kWorkerUrl),
658         base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
659                    true,
660                    run_loop.QuitClosure()));
661     run_loop.Run();
662   }
663   EXPECT_EQ(1, CountRenderProcessHosts());
664
665   // Registering again should succeed, although the algo still
666   // might not be complete.
667   {
668     base::RunLoop run_loop;
669     public_context()->RegisterServiceWorker(
670         embedded_test_server()->GetURL("/*"),
671         embedded_test_server()->GetURL(kWorkerUrl),
672         base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
673                    true,
674                    run_loop.QuitClosure()));
675     run_loop.Run();
676   }
677
678   // The registration algo might not be far enough along to have
679   // stored the registration data, so it may not be findable
680   // at this point.
681
682   // Unregistering something should return true.
683   {
684     base::RunLoop run_loop;
685     public_context()->UnregisterServiceWorker(
686         embedded_test_server()->GetURL("/*"),
687         base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
688                    true,
689                    run_loop.QuitClosure()));
690     run_loop.Run();
691   }
692   EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
693                                              "workers eagerly, so their RPHs "
694                                              "can still be running.";
695
696   // Should not be able to find it.
697   {
698     ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
699     GURL script_url;
700     RunOnIOThread(
701         base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
702                    this,
703                    embedded_test_server()->GetURL("/service_worker/empty.html"),
704                    &status,
705                    &script_url));
706     EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
707   }
708 }
709
710 }  // namespace content