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 "storage/browser/blob/blob_data_handle.h"
39 #include "storage/browser/blob/blob_storage_context.h"
40 #include "storage/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 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 ~WorkerActivatedObserver() override
{}
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
.Pass();
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 ~LongLivedResourceInterceptor() override
{}
197 // net::URLRequestInterceptor implementation
198 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
.version_id
!=
246 kInvalidServiceWorkerVersionId
)
247 version_id
= infos
[index
].installing_version
.version_id
;
248 else if (infos
[index
].waiting_version
.version_id
!=
249 kInvalidServiceWorkerVersionId
)
250 version_id
= infos
[1].waiting_version
.version_id
;
251 else if (infos
[index
].active_version
.version_id
!=
252 kInvalidServiceWorkerVersionId
)
253 version_id
= infos
[index
].active_version
.version_id
;
257 ServiceWorkerVersion
* version
=
258 wrapper
->context()->GetLiveVersion(version_id
);
259 *num_resources
= static_cast<int>(version
->script_cache_map()->size());
264 class ServiceWorkerBrowserTest
: public ContentBrowserTest
{
266 typedef ServiceWorkerBrowserTest self
;
268 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
269 command_line
->AppendSwitch(
270 switches::kEnableExperimentalWebPlatformFeatures
);
273 void SetUpOnMainThread() override
{
274 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
275 StoragePartition
* partition
= BrowserContext::GetDefaultStoragePartition(
276 shell()->web_contents()->GetBrowserContext());
277 wrapper_
= static_cast<ServiceWorkerContextWrapper
*>(
278 partition
->GetServiceWorkerContext());
280 // Navigate to the page to set up a renderer page (where we can embed
282 NavigateToURLBlockUntilNavigationsComplete(
284 embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
286 RunOnIOThread(base::Bind(&self::SetUpOnIOThread
, this));
289 void TearDownOnMainThread() override
{
290 RunOnIOThread(base::Bind(&self::TearDownOnIOThread
, this));
294 virtual void SetUpOnIOThread() {}
295 virtual void TearDownOnIOThread() {}
297 ServiceWorkerContextWrapper
* wrapper() { return wrapper_
.get(); }
298 ServiceWorkerContext
* public_context() { return wrapper(); }
300 void AssociateRendererProcessToPattern(const GURL
& pattern
) {
301 wrapper_
->process_manager()->AddProcessReferenceToPattern(
302 pattern
, shell()->web_contents()->GetRenderProcessHost()->GetID());
306 scoped_refptr
<ServiceWorkerContextWrapper
> wrapper_
;
309 class EmbeddedWorkerBrowserTest
: public ServiceWorkerBrowserTest
,
310 public EmbeddedWorkerInstance::Listener
{
312 typedef EmbeddedWorkerBrowserTest self
;
314 EmbeddedWorkerBrowserTest()
315 : last_worker_status_(EmbeddedWorkerInstance::STOPPED
),
316 pause_mode_(DONT_PAUSE
) {}
317 ~EmbeddedWorkerBrowserTest() override
{}
319 void TearDownOnIOThread() override
{
321 worker_
->RemoveListener(this);
326 void StartOnIOThread() {
327 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
328 worker_
= wrapper()->context()->embedded_worker_registry()->CreateWorker();
329 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED
, worker_
->status());
330 worker_
->AddListener(this);
333 const int64 service_worker_version_id
= 33L;
334 const GURL pattern
= embedded_test_server()->GetURL("/");
335 const GURL script_url
= embedded_test_server()->GetURL(
336 "/service_worker/worker.js");
337 AssociateRendererProcessToPattern(pattern
);
338 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
339 wrapper()->process_manager()->AddProcessReferenceToPattern(
340 pattern
, process_id
);
342 service_worker_version_id
,
345 pause_mode_
!= DONT_PAUSE
,
346 base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2
, this));
348 void StartOnIOThread2(ServiceWorkerStatusCode status
) {
349 last_worker_status_
= worker_
->status();
350 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
351 EXPECT_EQ(EmbeddedWorkerInstance::STARTING
, last_worker_status_
);
353 if (status
!= SERVICE_WORKER_OK
&& !done_closure_
.is_null())
357 void StopOnIOThread() {
358 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
359 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING
, worker_
->status());
361 ServiceWorkerStatusCode status
= worker_
->Stop();
363 last_worker_status_
= worker_
->status();
364 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
365 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING
, last_worker_status_
);
367 if (status
!= SERVICE_WORKER_OK
&& !done_closure_
.is_null())
372 // EmbeddedWorkerInstance::Observer overrides:
373 void OnStarted() override
{
374 ASSERT_TRUE(worker_
!= NULL
);
375 ASSERT_FALSE(done_closure_
.is_null());
376 last_worker_status_
= worker_
->status();
377 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, done_closure_
);
379 void OnStopped() override
{
380 ASSERT_TRUE(worker_
!= NULL
);
381 ASSERT_FALSE(done_closure_
.is_null());
382 last_worker_status_
= worker_
->status();
383 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, done_closure_
);
385 void OnPausedAfterDownload() override
{
386 if (pause_mode_
== PAUSE_THEN_RESUME
)
387 worker_
->ResumeAfterDownload();
388 else if (pause_mode_
== PAUSE_THEN_STOP
)
393 void OnReportException(const base::string16
& error_message
,
396 const GURL
& source_url
) override
{}
397 void OnReportConsoleMessage(int source_identifier
,
399 const base::string16
& message
,
401 const GURL
& source_url
) override
{}
402 bool OnMessageReceived(const IPC::Message
& message
) override
{ return false; }
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 ~ServiceWorkerVersionBrowserTest() override
{}
424 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 const GURL pattern
= embedded_test_server()->GetURL("/");
507 registration_
= new ServiceWorkerRegistration(
509 wrapper()->context()->storage()->NewRegistrationId(),
510 wrapper()->context()->AsWeakPtr());
511 version_
= new ServiceWorkerVersion(
513 embedded_test_server()->GetURL(worker_url
),
514 wrapper()->context()->storage()->NewVersionId(),
515 wrapper()->context()->AsWeakPtr());
516 AssociateRendererProcessToPattern(pattern
);
519 void StartOnIOThread(const base::Closure
& done
,
520 ServiceWorkerStatusCode
* result
) {
521 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
522 version_
->StartWorker(CreateReceiver(BrowserThread::UI
, done
, result
));
525 void InstallOnIOThread(const base::Closure
& done
,
526 ServiceWorkerStatusCode
* result
) {
527 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
528 version_
->SetStatus(ServiceWorkerVersion::INSTALLING
);
529 version_
->DispatchInstallEvent(
530 -1, CreateReceiver(BrowserThread::UI
, done
, result
));
533 void ActivateOnIOThread(const base::Closure
& done
,
534 ServiceWorkerStatusCode
* result
) {
535 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
536 version_
->SetStatus(ServiceWorkerVersion::ACTIVATING
);
537 version_
->DispatchActivateEvent(
538 CreateReceiver(BrowserThread::UI
, done
, result
));
541 void FetchOnIOThread(const base::Closure
& done
,
542 bool* prepare_result
,
543 FetchResult
* result
) {
544 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
545 ServiceWorkerFetchRequest
request(
546 embedded_test_server()->GetURL("/service_worker/empty.html"),
548 ServiceWorkerHeaderMap(),
551 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
552 version_
->DispatchFetchEvent(
554 CreatePrepareReceiver(prepare_result
),
555 CreateResponseReceiver(
556 BrowserThread::UI
, done
, blob_context_
.get(), result
));
559 void StopOnIOThread(const base::Closure
& done
,
560 ServiceWorkerStatusCode
* result
) {
561 ASSERT_TRUE(version_
.get());
562 version_
->StopWorker(CreateReceiver(BrowserThread::UI
, done
, result
));
565 void SyncEventOnIOThread(const base::Closure
& done
,
566 ServiceWorkerStatusCode
* result
) {
567 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
568 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
569 version_
->DispatchSyncEvent(
570 CreateReceiver(BrowserThread::UI
, done
, result
));
574 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
575 scoped_refptr
<ServiceWorkerVersion
> version_
;
576 scoped_refptr
<ChromeBlobStorageContext
> blob_context_
;
579 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest
, StartAndStop
) {
580 // Start a worker and wait until OnStarted() is called.
581 base::RunLoop start_run_loop
;
582 done_closure_
= start_run_loop
.QuitClosure();
583 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
584 base::Bind(&self::StartOnIOThread
, this));
585 start_run_loop
.Run();
587 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING
, last_worker_status_
);
589 // Stop a worker and wait until OnStopped() is called.
590 base::RunLoop stop_run_loop
;
591 done_closure_
= stop_run_loop
.QuitClosure();
592 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
593 base::Bind(&self::StopOnIOThread
, this));
596 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED
, last_worker_status_
);
599 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest
, StartPaused_ThenResume
) {
600 pause_mode_
= PAUSE_THEN_RESUME
;
601 base::RunLoop start_run_loop
;
602 done_closure_
= start_run_loop
.QuitClosure();
603 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
604 base::Bind(&self::StartOnIOThread
, this));
605 start_run_loop
.Run();
606 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING
, last_worker_status_
);
609 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest
,
610 StartPaused_ThenStop
) {
611 pause_mode_
= PAUSE_THEN_STOP
;
612 base::RunLoop start_run_loop
;
613 done_closure_
= start_run_loop
.QuitClosure();
614 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
615 base::Bind(&self::StartOnIOThread
, this));
616 start_run_loop
.Run();
617 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED
, last_worker_status_
);
620 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, StartAndStop
) {
621 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
622 "/service_worker/worker.js"));
625 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
626 base::RunLoop start_run_loop
;
627 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
628 base::Bind(&self::StartOnIOThread
, this,
629 start_run_loop
.QuitClosure(),
631 start_run_loop
.Run();
632 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
635 status
= SERVICE_WORKER_ERROR_FAILED
;
636 base::RunLoop stop_run_loop
;
637 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
638 base::Bind(&self::StopOnIOThread
, this,
639 stop_run_loop
.QuitClosure(),
642 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
645 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, StartNotFound
) {
646 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
647 "/service_worker/nonexistent.js"));
649 // Start a worker for nonexistent URL.
650 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
651 base::RunLoop start_run_loop
;
652 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
653 base::Bind(&self::StartOnIOThread
, this,
654 start_run_loop
.QuitClosure(),
656 start_run_loop
.Run();
657 ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED
, status
);
660 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, Install
) {
661 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK
);
664 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
665 InstallWithWaitUntil_Fulfilled
) {
666 InstallTestHelper("/service_worker/worker_install_fulfilled.js",
670 // Check that ServiceWorker script requests set a "Service-Worker: script"
672 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
673 ServiceWorkerScriptHeader
) {
674 embedded_test_server()->RegisterRequestHandler(
675 base::Bind(&VerifyServiceWorkerHeaderInRequest
));
676 InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK
);
679 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
680 Activate_NoEventListener
) {
681 ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK
);
682 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING
, version_
->status());
685 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, Activate_Rejected
) {
686 ActivateTestHelper("/service_worker/worker_activate_rejected.js",
687 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
);
690 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
691 InstallWithWaitUntil_Rejected
) {
692 InstallTestHelper("/service_worker/worker_install_rejected.js",
693 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
);
696 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, FetchEvent_Response
) {
697 ServiceWorkerFetchEventResult result
;
698 ServiceWorkerResponse response
;
699 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
700 FetchTestHelper("/service_worker/fetch_event.js",
701 &result
, &response
, &blob_data_handle
);
702 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE
, result
);
703 EXPECT_EQ(301, response
.status_code
);
704 EXPECT_EQ("Moved Permanently", response
.status_text
);
705 ServiceWorkerHeaderMap expected_headers
;
706 expected_headers
["content-language"] = "fi";
707 expected_headers
["content-type"] = "text/html; charset=UTF-8";
708 EXPECT_EQ(expected_headers
, response
.headers
);
712 base::Bind(&ReadResponseBody
,
713 &body
, base::Owned(blob_data_handle
.release())));
714 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body
);
717 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
718 SyncAbortedWithoutFlag
) {
719 RunOnIOThread(base::Bind(
720 &self::SetUpRegistrationOnIOThread
, this, "/service_worker/sync.js"));
722 // Run the sync event.
723 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
724 base::RunLoop sync_run_loop
;
725 BrowserThread::PostTask(BrowserThread::IO
,
727 base::Bind(&self::SyncEventOnIOThread
,
729 sync_run_loop
.QuitClosure(),
732 ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT
, status
);
735 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, SyncEventHandled
) {
736 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
737 command_line
->AppendSwitch(switches::kEnableServiceWorkerSync
);
739 RunOnIOThread(base::Bind(
740 &self::SetUpRegistrationOnIOThread
, this, "/service_worker/sync.js"));
741 ServiceWorkerFetchEventResult result
;
742 ServiceWorkerResponse response
;
743 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
744 // Should 404 before sync event.
745 FetchOnRegisteredWorker(&result
, &response
, &blob_data_handle
);
746 EXPECT_EQ(404, response
.status_code
);
748 // Run the sync event.
749 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
750 base::RunLoop sync_run_loop
;
751 BrowserThread::PostTask(BrowserThread::IO
,
753 base::Bind(&self::SyncEventOnIOThread
,
755 sync_run_loop
.QuitClosure(),
758 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
760 // Should 200 after sync event.
761 FetchOnRegisteredWorker(&result
, &response
, &blob_data_handle
);
762 EXPECT_EQ(200, response
.status_code
);
765 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
, Reload
) {
766 const std::string kPageUrl
= "/service_worker/reload.html";
767 const std::string kWorkerUrl
= "/service_worker/fetch_event_reload.js";
769 scoped_refptr
<WorkerActivatedObserver
> observer
=
770 new WorkerActivatedObserver(wrapper());
772 public_context()->RegisterServiceWorker(
773 embedded_test_server()->GetURL(kPageUrl
),
774 embedded_test_server()->GetURL(kWorkerUrl
),
775 base::Bind(&ExpectResultAndRun
, true, base::Bind(&base::DoNothing
)));
779 const base::string16 title
= base::ASCIIToUTF16("reload=false");
780 TitleWatcher
title_watcher(shell()->web_contents(), title
);
781 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl
));
782 EXPECT_EQ(title
, title_watcher
.WaitAndGetTitle());
785 const base::string16 title
= base::ASCIIToUTF16("reload=true");
786 TitleWatcher
title_watcher(shell()->web_contents(), title
);
787 ReloadBlockUntilNavigationsComplete(shell(), 1);
788 EXPECT_EQ(title
, title_watcher
.WaitAndGetTitle());
792 base::RunLoop run_loop
;
793 public_context()->UnregisterServiceWorker(
794 embedded_test_server()->GetURL(kPageUrl
),
795 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
800 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
, ImportsBustMemcache
) {
801 const std::string kScopeUrl
= "/service_worker/imports_bust_memcache_scope/";
802 const std::string kPageUrl
= "/service_worker/imports_bust_memcache.html";
803 const std::string kScriptUrl
= "/service_worker/worker_with_one_import.js";
804 const std::string kImportUrl
= "/service_worker/long_lived_import.js";
805 const base::string16
kOKTitle(base::ASCIIToUTF16("OK"));
806 const base::string16
kFailTitle(base::ASCIIToUTF16("FAIL"));
809 base::Bind(&CreateLongLivedResourceInterceptors
,
810 embedded_test_server()->GetURL(kScriptUrl
),
811 embedded_test_server()->GetURL(kImportUrl
)));
813 TitleWatcher
title_watcher(shell()->web_contents(), kOKTitle
);
814 title_watcher
.AlsoWaitForTitle(kFailTitle
);
815 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl
));
816 base::string16 title
= title_watcher
.WaitAndGetTitle();
817 EXPECT_EQ(kOKTitle
, title
);
819 // Verify the number of resources in the implicit script cache is correct.
820 const int kExpectedNumResources
= 2;
821 int num_resources
= 0;
823 base::Bind(&CountScriptResources
,
824 base::Unretained(wrapper()),
825 embedded_test_server()->GetURL(kScopeUrl
),
827 EXPECT_EQ(kExpectedNumResources
, num_resources
);
830 class ServiceWorkerBlackBoxBrowserTest
: public ServiceWorkerBrowserTest
{
832 typedef ServiceWorkerBlackBoxBrowserTest self
;
834 void FindRegistrationOnIO(const GURL
& document_url
,
835 ServiceWorkerStatusCode
* status
,
836 const base::Closure
& continuation
) {
837 wrapper()->context()->storage()->FindRegistrationForDocument(
839 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2
,
845 void FindRegistrationOnIO2(
846 ServiceWorkerStatusCode
* out_status
,
847 const base::Closure
& continuation
,
848 ServiceWorkerStatusCode status
,
849 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
850 *out_status
= status
;
851 if (!registration
.get())
852 EXPECT_NE(SERVICE_WORKER_OK
, status
);
857 static int CountRenderProcessHosts() {
859 for (RenderProcessHost::iterator
iter(RenderProcessHost::AllHostsIterator());
867 // Flaky timeouts on CrOS: http://crbug.com/387045
868 #if defined(OS_CHROMEOS)
869 #define MAYBE_Registration DISABLED_Registration
871 #define MAYBE_Registration Registration
873 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest
, MAYBE_Registration
) {
874 // Close the only window to be sure we're not re-using its RenderProcessHost.
876 EXPECT_EQ(0, CountRenderProcessHosts());
878 const std::string kWorkerUrl
= "/service_worker/fetch_event.js";
880 // Unregistering nothing should return false.
882 base::RunLoop run_loop
;
883 public_context()->UnregisterServiceWorker(
884 embedded_test_server()->GetURL("/"),
885 base::Bind(&ExpectResultAndRun
, false, run_loop
.QuitClosure()));
889 // If we use a worker URL that doesn't exist, registration fails.
891 base::RunLoop run_loop
;
892 public_context()->RegisterServiceWorker(
893 embedded_test_server()->GetURL("/"),
894 embedded_test_server()->GetURL("/does/not/exist"),
895 base::Bind(&ExpectResultAndRun
, false, run_loop
.QuitClosure()));
898 EXPECT_EQ(0, CountRenderProcessHosts());
900 // Register returns when the promise would be resolved.
902 base::RunLoop run_loop
;
903 public_context()->RegisterServiceWorker(
904 embedded_test_server()->GetURL("/"),
905 embedded_test_server()->GetURL(kWorkerUrl
),
906 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
909 EXPECT_EQ(1, CountRenderProcessHosts());
911 // Registering again should succeed, although the algo still
912 // might not be complete.
914 base::RunLoop run_loop
;
915 public_context()->RegisterServiceWorker(
916 embedded_test_server()->GetURL("/"),
917 embedded_test_server()->GetURL(kWorkerUrl
),
918 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
922 // The registration algo might not be far enough along to have
923 // stored the registration data, so it may not be findable
926 // Unregistering something should return true.
928 base::RunLoop run_loop
;
929 public_context()->UnregisterServiceWorker(
930 embedded_test_server()->GetURL("/"),
931 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
934 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
935 "workers eagerly, so their RPHs "
936 "can still be running.";
938 // Should not be able to find it.
940 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
942 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO
,
944 embedded_test_server()->GetURL("/service_worker/empty.html"),
946 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
, status
);
950 } // namespace content