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.
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 "webkit/browser/blob/blob_data_handle.h"
39 #include "webkit/browser/blob/blob_storage_context.h"
40 #include "webkit/common/blob/blob_data.h"
47 ServiceWorkerStatusCode status
;
48 ServiceWorkerFetchEventResult result
;
49 ServiceWorkerResponse response
;
50 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
53 void RunAndQuit(const base::Closure
& closure
,
54 const base::Closure
& quit
,
55 base::MessageLoopProxy
* original_message_loop
) {
57 original_message_loop
->PostTask(FROM_HERE
, quit
);
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()));
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(),
76 run_loop
.QuitClosure());
77 BrowserThread::PostTask(BrowserThread::IO
,
79 base::Bind(closure
, quit_on_original_thread
));
83 void ReceivePrepareResult(bool* is_prepared
) {
87 base::Closure
CreatePrepareReceiver(bool* is_prepared
) {
88 return base::Bind(&ReceivePrepareResult
, is_prepared
);
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
);
110 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit
);
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
),
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());
131 void ExpectResultAndRun(bool expected
,
132 const base::Closure
& continuation
,
134 EXPECT_EQ(expected
, actual
);
138 class WorkerActivatedObserver
139 : public ServiceWorkerContextObserver
,
140 public base::RefCountedThreadSafe
<WorkerActivatedObserver
> {
142 explicit WorkerActivatedObserver(ServiceWorkerContextWrapper
* context
)
143 : context_(context
) {}
145 RunOnIOThread(base::Bind(&WorkerActivatedObserver::InitOnIOThread
, this));
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
,
156 base::Bind(&WorkerActivatedObserver::Quit
, this));
159 void Wait() { run_loop_
.Run(); }
162 friend class base::RefCountedThreadSafe
<WorkerActivatedObserver
>;
163 virtual ~WorkerActivatedObserver() {}
164 void InitOnIOThread() { context_
->AddObserver(this); }
165 void Quit() { run_loop_
.Quit(); }
167 base::RunLoop run_loop_
;
168 ServiceWorkerContextWrapper
* context_
;
169 DISALLOW_COPY_AND_ASSIGN(WorkerActivatedObserver
);
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
);
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
>();
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
{
193 LongLivedResourceInterceptor(const std::string
& body
)
195 virtual ~LongLivedResourceInterceptor() {}
197 // net::URLRequestInterceptor implementation
198 virtual net::URLRequestJob
* MaybeInterceptRequest(
199 net::URLRequest
* request
,
200 net::NetworkDelegate
* network_delegate
) const OVERRIDE
{
201 const char kHeaders
[] =
203 "Content-Type: text/javascript\0"
204 "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
206 std::string
headers(kHeaders
, arraysize(kHeaders
));
207 return new net::URLRequestTestJob(
208 request
, network_delegate
, headers
, body_
, true);
213 DISALLOW_COPY_AND_ASSIGN(LongLivedResourceInterceptor
);
216 void CreateLongLivedResourceInterceptors(
217 const GURL
& worker_url
, const GURL
& import_url
) {
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
219 scoped_ptr
<net::URLRequestInterceptor
> interceptor
;
221 interceptor
.reset(new LongLivedResourceInterceptor(
222 "importScripts('long_lived_import.js');"));
223 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
224 worker_url
, interceptor
.Pass());
226 interceptor
.reset(new LongLivedResourceInterceptor(
227 "// the imported script does nothing"));
228 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
229 import_url
, interceptor
.Pass());
232 void CountScriptResources(
233 ServiceWorkerContextWrapper
* wrapper
,
235 int* num_resources
) {
238 std::vector
<ServiceWorkerRegistrationInfo
> infos
=
239 wrapper
->context()->GetAllLiveRegistrationInfo();
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
;
254 ServiceWorkerVersion
* version
=
255 wrapper
->context()->GetLiveVersion(version_id
);
256 *num_resources
= static_cast<int>(version
->script_cache_map()->size());
261 class ServiceWorkerBrowserTest
: public ContentBrowserTest
{
263 typedef ServiceWorkerBrowserTest self
;
265 virtual void SetUpCommandLine(base::CommandLine
* command_line
) OVERRIDE
{
266 command_line
->AppendSwitch(
267 switches::kEnableExperimentalWebPlatformFeatures
);
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());
277 // Navigate to the page to set up a renderer page (where we can embed
279 NavigateToURLBlockUntilNavigationsComplete(
281 embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
283 RunOnIOThread(base::Bind(&self::SetUpOnIOThread
, this));
286 virtual void TearDownOnMainThread() OVERRIDE
{
287 RunOnIOThread(base::Bind(&self::TearDownOnIOThread
, this));
291 virtual void SetUpOnIOThread() {}
292 virtual void TearDownOnIOThread() {}
294 ServiceWorkerContextWrapper
* wrapper() { return wrapper_
.get(); }
295 ServiceWorkerContext
* public_context() { return wrapper(); }
297 void AssociateRendererProcessToWorker(EmbeddedWorkerInstance
* worker
) {
298 worker
->AddProcessReference(
299 shell()->web_contents()->GetRenderProcessHost()->GetID());
303 scoped_refptr
<ServiceWorkerContextWrapper
> wrapper_
;
306 class EmbeddedWorkerBrowserTest
: public ServiceWorkerBrowserTest
,
307 public EmbeddedWorkerInstance::Listener
{
309 typedef EmbeddedWorkerBrowserTest self
;
311 EmbeddedWorkerBrowserTest()
312 : last_worker_status_(EmbeddedWorkerInstance::STOPPED
),
313 pause_mode_(DONT_PAUSE
) {}
314 virtual ~EmbeddedWorkerBrowserTest() {}
316 virtual void TearDownOnIOThread() OVERRIDE
{
318 worker_
->RemoveListener(this);
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);
329 AssociateRendererProcessToWorker(worker_
.get());
331 const int64 service_worker_version_id
= 33L;
332 const GURL scope
= embedded_test_server()->GetURL("/");
333 const GURL script_url
= embedded_test_server()->GetURL(
334 "/service_worker/worker.js");
335 std::vector
<int> processes
;
337 shell()->web_contents()->GetRenderProcessHost()->GetID());
339 service_worker_version_id
,
342 pause_mode_
!= DONT_PAUSE
,
344 base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2
, this));
346 void StartOnIOThread2(ServiceWorkerStatusCode status
) {
347 last_worker_status_
= worker_
->status();
348 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
349 EXPECT_EQ(EmbeddedWorkerInstance::STARTING
, last_worker_status_
);
351 if (status
!= SERVICE_WORKER_OK
&& !done_closure_
.is_null())
355 void StopOnIOThread() {
356 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
357 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING
, worker_
->status());
359 ServiceWorkerStatusCode status
= worker_
->Stop();
361 last_worker_status_
= worker_
->status();
362 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
363 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING
, last_worker_status_
);
365 if (status
!= SERVICE_WORKER_OK
&& !done_closure_
.is_null())
370 // EmbeddedWorkerInstance::Observer overrides:
371 virtual void OnStarted() OVERRIDE
{
372 ASSERT_TRUE(worker_
!= NULL
);
373 ASSERT_FALSE(done_closure_
.is_null());
374 last_worker_status_
= worker_
->status();
375 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, done_closure_
);
377 virtual void OnStopped() OVERRIDE
{
378 ASSERT_TRUE(worker_
!= NULL
);
379 ASSERT_FALSE(done_closure_
.is_null());
380 last_worker_status_
= worker_
->status();
381 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, done_closure_
);
383 virtual void OnPausedAfterDownload() OVERRIDE
{
384 if (pause_mode_
== PAUSE_THEN_RESUME
)
385 worker_
->ResumeAfterDownload();
386 else if (pause_mode_
== PAUSE_THEN_STOP
)
391 virtual void OnReportException(const base::string16
& error_message
,
394 const GURL
& source_url
) OVERRIDE
{}
395 virtual void OnReportConsoleMessage(int source_identifier
,
397 const base::string16
& message
,
399 const GURL
& source_url
) OVERRIDE
{}
400 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
404 scoped_ptr
<EmbeddedWorkerInstance
> worker_
;
405 EmbeddedWorkerInstance::Status last_worker_status_
;
413 // Called by EmbeddedWorkerInstance::Observer overrides so that
414 // test code can wait for the worker status notifications.
415 base::Closure done_closure_
;
418 class ServiceWorkerVersionBrowserTest
: public ServiceWorkerBrowserTest
{
420 typedef ServiceWorkerVersionBrowserTest self
;
422 virtual ~ServiceWorkerVersionBrowserTest() {}
424 virtual void TearDownOnIOThread() OVERRIDE
{
425 registration_
= NULL
;
429 void InstallTestHelper(const std::string
& worker_url
,
430 ServiceWorkerStatusCode expected_status
) {
431 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
434 // Dispatch install on a worker.
435 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
436 base::RunLoop install_run_loop
;
437 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
438 base::Bind(&self::InstallOnIOThread
, this,
439 install_run_loop
.QuitClosure(),
441 install_run_loop
.Run();
442 ASSERT_EQ(expected_status
, status
);
445 status
= SERVICE_WORKER_ERROR_FAILED
;
446 base::RunLoop stop_run_loop
;
447 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
448 base::Bind(&self::StopOnIOThread
, this,
449 stop_run_loop
.QuitClosure(),
452 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
455 void ActivateTestHelper(
456 const std::string
& worker_url
,
457 ServiceWorkerStatusCode expected_status
) {
459 base::Bind(&self::SetUpRegistrationOnIOThread
, this, worker_url
));
460 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
461 base::RunLoop run_loop
;
462 BrowserThread::PostTask(
466 &self::ActivateOnIOThread
, this, run_loop
.QuitClosure(), &status
));
468 ASSERT_EQ(expected_status
, status
);
471 void FetchOnRegisteredWorker(
472 ServiceWorkerFetchEventResult
* result
,
473 ServiceWorkerResponse
* response
,
474 scoped_ptr
<storage::BlobDataHandle
>* blob_data_handle
) {
475 blob_context_
= ChromeBlobStorageContext::GetFor(
476 shell()->web_contents()->GetBrowserContext());
477 bool prepare_result
= false;
478 FetchResult fetch_result
;
479 fetch_result
.status
= SERVICE_WORKER_ERROR_FAILED
;
480 base::RunLoop fetch_run_loop
;
481 BrowserThread::PostTask(BrowserThread::IO
,
483 base::Bind(&self::FetchOnIOThread
,
485 fetch_run_loop
.QuitClosure(),
488 fetch_run_loop
.Run();
489 ASSERT_TRUE(prepare_result
);
490 *result
= fetch_result
.result
;
491 *response
= fetch_result
.response
;
492 *blob_data_handle
= fetch_result
.blob_data_handle
.Pass();
493 ASSERT_EQ(SERVICE_WORKER_OK
, fetch_result
.status
);
496 void FetchTestHelper(const std::string
& worker_url
,
497 ServiceWorkerFetchEventResult
* result
,
498 ServiceWorkerResponse
* response
,
499 scoped_ptr
<storage::BlobDataHandle
>* blob_data_handle
) {
501 base::Bind(&self::SetUpRegistrationOnIOThread
, this, worker_url
));
502 FetchOnRegisteredWorker(result
, response
, blob_data_handle
);
505 void SetUpRegistrationOnIOThread(const std::string
& worker_url
) {
506 registration_
= new ServiceWorkerRegistration(
507 embedded_test_server()->GetURL("/"),
508 wrapper()->context()->storage()->NewRegistrationId(),
509 wrapper()->context()->AsWeakPtr());
510 version_
= new ServiceWorkerVersion(
512 embedded_test_server()->GetURL(worker_url
),
513 wrapper()->context()->storage()->NewVersionId(),
514 wrapper()->context()->AsWeakPtr());
515 AssociateRendererProcessToWorker(version_
->embedded_worker());
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
));
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
));
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
));
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"),
547 std::map
<std::string
, std::string
>(),
550 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
551 version_
->DispatchFetchEvent(
553 CreatePrepareReceiver(prepare_result
),
554 CreateResponseReceiver(
555 BrowserThread::UI
, done
, blob_context_
.get(), result
));
558 void StopOnIOThread(const base::Closure
& done
,
559 ServiceWorkerStatusCode
* result
) {
560 ASSERT_TRUE(version_
.get());
561 version_
->StopWorker(CreateReceiver(BrowserThread::UI
, done
, result
));
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
));
573 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
574 scoped_refptr
<ServiceWorkerVersion
> version_
;
575 scoped_refptr
<ChromeBlobStorageContext
> blob_context_
;
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();
586 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING
, last_worker_status_
);
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));
595 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED
, last_worker_status_
);
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_
);
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_
);
619 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, StartAndStop
) {
620 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
621 "/service_worker/worker.js"));
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(),
630 start_run_loop
.Run();
631 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
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(),
641 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
644 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, StartNotFound
) {
645 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
646 "/service_worker/nonexistent.js"));
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(),
655 start_run_loop
.Run();
656 ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED
, status
);
659 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, Install
) {
660 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK
);
663 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
664 InstallWithWaitUntil_Fulfilled
) {
665 InstallTestHelper("/service_worker/worker_install_fulfilled.js",
669 // Check that ServiceWorker script requests set a "Service-Worker: script"
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
);
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());
684 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, Activate_Rejected
) {
685 ActivateTestHelper("/service_worker/worker_activate_rejected.js",
686 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
);
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
);
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 std::map
<std::string
, std::string
> 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
);
711 base::Bind(&ReadResponseBody
,
712 &body
, base::Owned(blob_data_handle
.release())));
713 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body
);
716 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
717 SyncAbortedWithoutFlag
) {
718 RunOnIOThread(base::Bind(
719 &self::SetUpRegistrationOnIOThread
, this, "/service_worker/sync.js"));
721 // Run the sync event.
722 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
723 base::RunLoop sync_run_loop
;
724 BrowserThread::PostTask(BrowserThread::IO
,
726 base::Bind(&self::SyncEventOnIOThread
,
728 sync_run_loop
.QuitClosure(),
731 ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT
, status
);
734 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, SyncEventHandled
) {
735 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
736 command_line
->AppendSwitch(switches::kEnableServiceWorkerSync
);
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
);
747 // Run the sync event.
748 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
749 base::RunLoop sync_run_loop
;
750 BrowserThread::PostTask(BrowserThread::IO
,
752 base::Bind(&self::SyncEventOnIOThread
,
754 sync_run_loop
.QuitClosure(),
757 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
759 // Should 200 after sync event.
760 FetchOnRegisteredWorker(&result
, &response
, &blob_data_handle
);
761 EXPECT_EQ(200, response
.status_code
);
764 // ServiceWorkerBrowserTest.Reload is flaky on Android crbug.com/393486
765 #if defined(OS_ANDROID)
766 #define MAYBE_Reload DISABLED_Reload
768 #define MAYBE_Reload Reload
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";
774 scoped_refptr
<WorkerActivatedObserver
> observer
=
775 new WorkerActivatedObserver(wrapper());
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
)));
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());
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());
797 base::RunLoop run_loop
;
798 public_context()->UnregisterServiceWorker(
799 embedded_test_server()->GetURL(kPageUrl
),
800 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
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"));
814 base::Bind(&CreateLongLivedResourceInterceptors
,
815 embedded_test_server()->GetURL(kScriptUrl
),
816 embedded_test_server()->GetURL(kImportUrl
)));
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
);
824 // Verify the number of resources in the implicit script cache is correct.
825 const int kExpectedNumResources
= 2;
826 int num_resources
= 0;
828 base::Bind(&CountScriptResources
,
829 base::Unretained(wrapper()),
830 embedded_test_server()->GetURL(kScopeUrl
),
832 EXPECT_EQ(kExpectedNumResources
, num_resources
);
835 class ServiceWorkerBlackBoxBrowserTest
: public ServiceWorkerBrowserTest
{
837 typedef ServiceWorkerBlackBoxBrowserTest self
;
839 void FindRegistrationOnIO(const GURL
& document_url
,
840 ServiceWorkerStatusCode
* status
,
841 const base::Closure
& continuation
) {
842 wrapper()->context()->storage()->FindRegistrationForDocument(
844 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2
,
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
);
862 static int CountRenderProcessHosts() {
864 for (RenderProcessHost::iterator
iter(RenderProcessHost::AllHostsIterator());
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
876 #define MAYBE_Registration Registration
878 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest
, MAYBE_Registration
) {
879 // Close the only window to be sure we're not re-using its RenderProcessHost.
881 EXPECT_EQ(0, CountRenderProcessHosts());
883 const std::string kWorkerUrl
= "/service_worker/fetch_event.js";
885 // Unregistering nothing should return true.
887 base::RunLoop run_loop
;
888 public_context()->UnregisterServiceWorker(
889 embedded_test_server()->GetURL("/"),
890 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
894 // If we use a worker URL that doesn't exist, registration fails.
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()));
903 EXPECT_EQ(0, CountRenderProcessHosts());
905 // Register returns when the promise would be resolved.
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()));
914 EXPECT_EQ(1, CountRenderProcessHosts());
916 // Registering again should succeed, although the algo still
917 // might not be complete.
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()));
927 // The registration algo might not be far enough along to have
928 // stored the registration data, so it may not be findable
931 // Unregistering something should return true.
933 base::RunLoop run_loop
;
934 public_context()->UnregisterServiceWorker(
935 embedded_test_server()->GetURL("/"),
936 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
939 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
940 "workers eagerly, so their RPHs "
941 "can still be running.";
943 // Should not be able to find it.
945 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
947 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO
,
949 embedded_test_server()->GetURL("/service_worker/empty.html"),
951 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
, status
);
955 } // namespace content