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
.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 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
266 command_line
->AppendSwitch(
267 switches::kEnableExperimentalWebPlatformFeatures
);
270 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 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 AssociateRendererProcessToPattern(const GURL
& pattern
) {
298 wrapper_
->process_manager()->AddProcessReferenceToPattern(
299 pattern
, 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 ~EmbeddedWorkerBrowserTest() override
{}
316 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);
330 const int64 service_worker_version_id
= 33L;
331 const GURL pattern
= embedded_test_server()->GetURL("/");
332 const GURL script_url
= embedded_test_server()->GetURL(
333 "/service_worker/worker.js");
334 AssociateRendererProcessToPattern(pattern
);
335 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
336 wrapper()->process_manager()->AddProcessReferenceToPattern(
337 pattern
, process_id
);
339 service_worker_version_id
,
342 pause_mode_
!= DONT_PAUSE
,
343 base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2
, this));
345 void StartOnIOThread2(ServiceWorkerStatusCode status
) {
346 last_worker_status_
= worker_
->status();
347 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
348 EXPECT_EQ(EmbeddedWorkerInstance::STARTING
, last_worker_status_
);
350 if (status
!= SERVICE_WORKER_OK
&& !done_closure_
.is_null())
354 void StopOnIOThread() {
355 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
356 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING
, worker_
->status());
358 ServiceWorkerStatusCode status
= worker_
->Stop();
360 last_worker_status_
= worker_
->status();
361 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
362 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING
, last_worker_status_
);
364 if (status
!= SERVICE_WORKER_OK
&& !done_closure_
.is_null())
369 // EmbeddedWorkerInstance::Observer overrides:
370 void OnStarted() override
{
371 ASSERT_TRUE(worker_
!= NULL
);
372 ASSERT_FALSE(done_closure_
.is_null());
373 last_worker_status_
= worker_
->status();
374 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, done_closure_
);
376 void OnStopped() override
{
377 ASSERT_TRUE(worker_
!= NULL
);
378 ASSERT_FALSE(done_closure_
.is_null());
379 last_worker_status_
= worker_
->status();
380 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, done_closure_
);
382 void OnPausedAfterDownload() override
{
383 if (pause_mode_
== PAUSE_THEN_RESUME
)
384 worker_
->ResumeAfterDownload();
385 else if (pause_mode_
== PAUSE_THEN_STOP
)
390 void OnReportException(const base::string16
& error_message
,
393 const GURL
& source_url
) override
{}
394 void OnReportConsoleMessage(int source_identifier
,
396 const base::string16
& message
,
398 const GURL
& source_url
) override
{}
399 bool OnMessageReceived(const IPC::Message
& message
) override
{ return false; }
401 scoped_ptr
<EmbeddedWorkerInstance
> worker_
;
402 EmbeddedWorkerInstance::Status last_worker_status_
;
410 // Called by EmbeddedWorkerInstance::Observer overrides so that
411 // test code can wait for the worker status notifications.
412 base::Closure done_closure_
;
415 class ServiceWorkerVersionBrowserTest
: public ServiceWorkerBrowserTest
{
417 typedef ServiceWorkerVersionBrowserTest self
;
419 ~ServiceWorkerVersionBrowserTest() override
{}
421 void TearDownOnIOThread() override
{
422 registration_
= NULL
;
426 void InstallTestHelper(const std::string
& worker_url
,
427 ServiceWorkerStatusCode expected_status
) {
428 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
431 // Dispatch install on a worker.
432 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
433 base::RunLoop install_run_loop
;
434 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
435 base::Bind(&self::InstallOnIOThread
, this,
436 install_run_loop
.QuitClosure(),
438 install_run_loop
.Run();
439 ASSERT_EQ(expected_status
, status
);
442 status
= SERVICE_WORKER_ERROR_FAILED
;
443 base::RunLoop stop_run_loop
;
444 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
445 base::Bind(&self::StopOnIOThread
, this,
446 stop_run_loop
.QuitClosure(),
449 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
452 void ActivateTestHelper(
453 const std::string
& worker_url
,
454 ServiceWorkerStatusCode expected_status
) {
456 base::Bind(&self::SetUpRegistrationOnIOThread
, this, worker_url
));
457 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
458 base::RunLoop run_loop
;
459 BrowserThread::PostTask(
463 &self::ActivateOnIOThread
, this, run_loop
.QuitClosure(), &status
));
465 ASSERT_EQ(expected_status
, status
);
468 void FetchOnRegisteredWorker(
469 ServiceWorkerFetchEventResult
* result
,
470 ServiceWorkerResponse
* response
,
471 scoped_ptr
<storage::BlobDataHandle
>* blob_data_handle
) {
472 blob_context_
= ChromeBlobStorageContext::GetFor(
473 shell()->web_contents()->GetBrowserContext());
474 bool prepare_result
= false;
475 FetchResult fetch_result
;
476 fetch_result
.status
= SERVICE_WORKER_ERROR_FAILED
;
477 base::RunLoop fetch_run_loop
;
478 BrowserThread::PostTask(BrowserThread::IO
,
480 base::Bind(&self::FetchOnIOThread
,
482 fetch_run_loop
.QuitClosure(),
485 fetch_run_loop
.Run();
486 ASSERT_TRUE(prepare_result
);
487 *result
= fetch_result
.result
;
488 *response
= fetch_result
.response
;
489 *blob_data_handle
= fetch_result
.blob_data_handle
.Pass();
490 ASSERT_EQ(SERVICE_WORKER_OK
, fetch_result
.status
);
493 void FetchTestHelper(const std::string
& worker_url
,
494 ServiceWorkerFetchEventResult
* result
,
495 ServiceWorkerResponse
* response
,
496 scoped_ptr
<storage::BlobDataHandle
>* blob_data_handle
) {
498 base::Bind(&self::SetUpRegistrationOnIOThread
, this, worker_url
));
499 FetchOnRegisteredWorker(result
, response
, blob_data_handle
);
502 void SetUpRegistrationOnIOThread(const std::string
& worker_url
) {
503 const GURL pattern
= embedded_test_server()->GetURL("/");
504 registration_
= new ServiceWorkerRegistration(
506 wrapper()->context()->storage()->NewRegistrationId(),
507 wrapper()->context()->AsWeakPtr());
508 version_
= new ServiceWorkerVersion(
510 embedded_test_server()->GetURL(worker_url
),
511 wrapper()->context()->storage()->NewVersionId(),
512 wrapper()->context()->AsWeakPtr());
513 AssociateRendererProcessToPattern(pattern
);
516 void StartOnIOThread(const base::Closure
& done
,
517 ServiceWorkerStatusCode
* result
) {
518 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
519 version_
->StartWorker(CreateReceiver(BrowserThread::UI
, done
, result
));
522 void InstallOnIOThread(const base::Closure
& done
,
523 ServiceWorkerStatusCode
* result
) {
524 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
525 version_
->SetStatus(ServiceWorkerVersion::INSTALLING
);
526 version_
->DispatchInstallEvent(
527 -1, CreateReceiver(BrowserThread::UI
, done
, result
));
530 void ActivateOnIOThread(const base::Closure
& done
,
531 ServiceWorkerStatusCode
* result
) {
532 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
533 version_
->SetStatus(ServiceWorkerVersion::ACTIVATING
);
534 version_
->DispatchActivateEvent(
535 CreateReceiver(BrowserThread::UI
, done
, result
));
538 void FetchOnIOThread(const base::Closure
& done
,
539 bool* prepare_result
,
540 FetchResult
* result
) {
541 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
542 ServiceWorkerFetchRequest
request(
543 embedded_test_server()->GetURL("/service_worker/empty.html"),
545 ServiceWorkerHeaderMap(),
548 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
549 version_
->DispatchFetchEvent(
551 CreatePrepareReceiver(prepare_result
),
552 CreateResponseReceiver(
553 BrowserThread::UI
, done
, blob_context_
.get(), result
));
556 void StopOnIOThread(const base::Closure
& done
,
557 ServiceWorkerStatusCode
* result
) {
558 ASSERT_TRUE(version_
.get());
559 version_
->StopWorker(CreateReceiver(BrowserThread::UI
, done
, result
));
562 void SyncEventOnIOThread(const base::Closure
& done
,
563 ServiceWorkerStatusCode
* result
) {
564 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
565 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
566 version_
->DispatchSyncEvent(
567 CreateReceiver(BrowserThread::UI
, done
, result
));
571 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
572 scoped_refptr
<ServiceWorkerVersion
> version_
;
573 scoped_refptr
<ChromeBlobStorageContext
> blob_context_
;
576 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest
, StartAndStop
) {
577 // Start a worker and wait until OnStarted() is called.
578 base::RunLoop start_run_loop
;
579 done_closure_
= start_run_loop
.QuitClosure();
580 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
581 base::Bind(&self::StartOnIOThread
, this));
582 start_run_loop
.Run();
584 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING
, last_worker_status_
);
586 // Stop a worker and wait until OnStopped() is called.
587 base::RunLoop stop_run_loop
;
588 done_closure_
= stop_run_loop
.QuitClosure();
589 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
590 base::Bind(&self::StopOnIOThread
, this));
593 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED
, last_worker_status_
);
596 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest
, StartPaused_ThenResume
) {
597 pause_mode_
= PAUSE_THEN_RESUME
;
598 base::RunLoop start_run_loop
;
599 done_closure_
= start_run_loop
.QuitClosure();
600 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
601 base::Bind(&self::StartOnIOThread
, this));
602 start_run_loop
.Run();
603 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING
, last_worker_status_
);
606 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest
,
607 StartPaused_ThenStop
) {
608 pause_mode_
= PAUSE_THEN_STOP
;
609 base::RunLoop start_run_loop
;
610 done_closure_
= start_run_loop
.QuitClosure();
611 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
612 base::Bind(&self::StartOnIOThread
, this));
613 start_run_loop
.Run();
614 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED
, last_worker_status_
);
617 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, StartAndStop
) {
618 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
619 "/service_worker/worker.js"));
622 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
623 base::RunLoop start_run_loop
;
624 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
625 base::Bind(&self::StartOnIOThread
, this,
626 start_run_loop
.QuitClosure(),
628 start_run_loop
.Run();
629 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
632 status
= SERVICE_WORKER_ERROR_FAILED
;
633 base::RunLoop stop_run_loop
;
634 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
635 base::Bind(&self::StopOnIOThread
, this,
636 stop_run_loop
.QuitClosure(),
639 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
642 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, StartNotFound
) {
643 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
644 "/service_worker/nonexistent.js"));
646 // Start a worker for nonexistent URL.
647 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
648 base::RunLoop start_run_loop
;
649 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
650 base::Bind(&self::StartOnIOThread
, this,
651 start_run_loop
.QuitClosure(),
653 start_run_loop
.Run();
654 ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED
, status
);
657 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, Install
) {
658 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK
);
661 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
662 InstallWithWaitUntil_Fulfilled
) {
663 InstallTestHelper("/service_worker/worker_install_fulfilled.js",
667 // Check that ServiceWorker script requests set a "Service-Worker: script"
669 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
670 ServiceWorkerScriptHeader
) {
671 embedded_test_server()->RegisterRequestHandler(
672 base::Bind(&VerifyServiceWorkerHeaderInRequest
));
673 InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK
);
676 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
677 Activate_NoEventListener
) {
678 ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK
);
679 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING
, version_
->status());
682 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, Activate_Rejected
) {
683 ActivateTestHelper("/service_worker/worker_activate_rejected.js",
684 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
);
687 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
688 InstallWithWaitUntil_Rejected
) {
689 InstallTestHelper("/service_worker/worker_install_rejected.js",
690 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
);
693 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, FetchEvent_Response
) {
694 ServiceWorkerFetchEventResult result
;
695 ServiceWorkerResponse response
;
696 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
697 FetchTestHelper("/service_worker/fetch_event.js",
698 &result
, &response
, &blob_data_handle
);
699 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE
, result
);
700 EXPECT_EQ(301, response
.status_code
);
701 EXPECT_EQ("Moved Permanently", response
.status_text
);
702 ServiceWorkerHeaderMap expected_headers
;
703 expected_headers
["content-language"] = "fi";
704 expected_headers
["content-type"] = "text/html; charset=UTF-8";
705 EXPECT_EQ(expected_headers
, response
.headers
);
709 base::Bind(&ReadResponseBody
,
710 &body
, base::Owned(blob_data_handle
.release())));
711 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body
);
714 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
715 SyncAbortedWithoutFlag
) {
716 RunOnIOThread(base::Bind(
717 &self::SetUpRegistrationOnIOThread
, this, "/service_worker/sync.js"));
719 // Run the sync event.
720 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
721 base::RunLoop sync_run_loop
;
722 BrowserThread::PostTask(BrowserThread::IO
,
724 base::Bind(&self::SyncEventOnIOThread
,
726 sync_run_loop
.QuitClosure(),
729 ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT
, status
);
732 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, SyncEventHandled
) {
733 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
734 command_line
->AppendSwitch(switches::kEnableServiceWorkerSync
);
736 RunOnIOThread(base::Bind(
737 &self::SetUpRegistrationOnIOThread
, this, "/service_worker/sync.js"));
738 ServiceWorkerFetchEventResult result
;
739 ServiceWorkerResponse response
;
740 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
741 // Should 404 before sync event.
742 FetchOnRegisteredWorker(&result
, &response
, &blob_data_handle
);
743 EXPECT_EQ(404, response
.status_code
);
745 // Run the sync event.
746 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
747 base::RunLoop sync_run_loop
;
748 BrowserThread::PostTask(BrowserThread::IO
,
750 base::Bind(&self::SyncEventOnIOThread
,
752 sync_run_loop
.QuitClosure(),
755 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
757 // Should 200 after sync event.
758 FetchOnRegisteredWorker(&result
, &response
, &blob_data_handle
);
759 EXPECT_EQ(200, response
.status_code
);
762 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
, Reload
) {
763 const std::string kPageUrl
= "/service_worker/reload.html";
764 const std::string kWorkerUrl
= "/service_worker/fetch_event_reload.js";
766 scoped_refptr
<WorkerActivatedObserver
> observer
=
767 new WorkerActivatedObserver(wrapper());
769 public_context()->RegisterServiceWorker(
770 embedded_test_server()->GetURL(kPageUrl
),
771 embedded_test_server()->GetURL(kWorkerUrl
),
772 base::Bind(&ExpectResultAndRun
, true, base::Bind(&base::DoNothing
)));
776 const base::string16 title
= base::ASCIIToUTF16("reload=false");
777 TitleWatcher
title_watcher(shell()->web_contents(), title
);
778 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl
));
779 EXPECT_EQ(title
, title_watcher
.WaitAndGetTitle());
782 const base::string16 title
= base::ASCIIToUTF16("reload=true");
783 TitleWatcher
title_watcher(shell()->web_contents(), title
);
784 ReloadBlockUntilNavigationsComplete(shell(), 1);
785 EXPECT_EQ(title
, title_watcher
.WaitAndGetTitle());
789 base::RunLoop run_loop
;
790 public_context()->UnregisterServiceWorker(
791 embedded_test_server()->GetURL(kPageUrl
),
792 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
797 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
, ImportsBustMemcache
) {
798 const std::string kScopeUrl
= "/service_worker/imports_bust_memcache_scope/";
799 const std::string kPageUrl
= "/service_worker/imports_bust_memcache.html";
800 const std::string kScriptUrl
= "/service_worker/worker_with_one_import.js";
801 const std::string kImportUrl
= "/service_worker/long_lived_import.js";
802 const base::string16
kOKTitle(base::ASCIIToUTF16("OK"));
803 const base::string16
kFailTitle(base::ASCIIToUTF16("FAIL"));
806 base::Bind(&CreateLongLivedResourceInterceptors
,
807 embedded_test_server()->GetURL(kScriptUrl
),
808 embedded_test_server()->GetURL(kImportUrl
)));
810 TitleWatcher
title_watcher(shell()->web_contents(), kOKTitle
);
811 title_watcher
.AlsoWaitForTitle(kFailTitle
);
812 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl
));
813 base::string16 title
= title_watcher
.WaitAndGetTitle();
814 EXPECT_EQ(kOKTitle
, title
);
816 // Verify the number of resources in the implicit script cache is correct.
817 const int kExpectedNumResources
= 2;
818 int num_resources
= 0;
820 base::Bind(&CountScriptResources
,
821 base::Unretained(wrapper()),
822 embedded_test_server()->GetURL(kScopeUrl
),
824 EXPECT_EQ(kExpectedNumResources
, num_resources
);
827 class ServiceWorkerBlackBoxBrowserTest
: public ServiceWorkerBrowserTest
{
829 typedef ServiceWorkerBlackBoxBrowserTest self
;
831 void FindRegistrationOnIO(const GURL
& document_url
,
832 ServiceWorkerStatusCode
* status
,
833 const base::Closure
& continuation
) {
834 wrapper()->context()->storage()->FindRegistrationForDocument(
836 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2
,
842 void FindRegistrationOnIO2(
843 ServiceWorkerStatusCode
* out_status
,
844 const base::Closure
& continuation
,
845 ServiceWorkerStatusCode status
,
846 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
847 *out_status
= status
;
848 if (!registration
.get())
849 EXPECT_NE(SERVICE_WORKER_OK
, status
);
854 static int CountRenderProcessHosts() {
856 for (RenderProcessHost::iterator
iter(RenderProcessHost::AllHostsIterator());
864 // Flaky timeouts on CrOS: http://crbug.com/387045
865 #if defined(OS_CHROMEOS)
866 #define MAYBE_Registration DISABLED_Registration
868 #define MAYBE_Registration Registration
870 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest
, MAYBE_Registration
) {
871 // Close the only window to be sure we're not re-using its RenderProcessHost.
873 EXPECT_EQ(0, CountRenderProcessHosts());
875 const std::string kWorkerUrl
= "/service_worker/fetch_event.js";
877 // Unregistering nothing should return false.
879 base::RunLoop run_loop
;
880 public_context()->UnregisterServiceWorker(
881 embedded_test_server()->GetURL("/"),
882 base::Bind(&ExpectResultAndRun
, false, run_loop
.QuitClosure()));
886 // If we use a worker URL that doesn't exist, registration fails.
888 base::RunLoop run_loop
;
889 public_context()->RegisterServiceWorker(
890 embedded_test_server()->GetURL("/"),
891 embedded_test_server()->GetURL("/does/not/exist"),
892 base::Bind(&ExpectResultAndRun
, false, run_loop
.QuitClosure()));
895 EXPECT_EQ(0, CountRenderProcessHosts());
897 // Register returns when the promise would be resolved.
899 base::RunLoop run_loop
;
900 public_context()->RegisterServiceWorker(
901 embedded_test_server()->GetURL("/"),
902 embedded_test_server()->GetURL(kWorkerUrl
),
903 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
906 EXPECT_EQ(1, CountRenderProcessHosts());
908 // Registering again should succeed, although the algo still
909 // might not be complete.
911 base::RunLoop run_loop
;
912 public_context()->RegisterServiceWorker(
913 embedded_test_server()->GetURL("/"),
914 embedded_test_server()->GetURL(kWorkerUrl
),
915 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
919 // The registration algo might not be far enough along to have
920 // stored the registration data, so it may not be findable
923 // Unregistering something should return true.
925 base::RunLoop run_loop
;
926 public_context()->UnregisterServiceWorker(
927 embedded_test_server()->GetURL("/"),
928 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
931 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
932 "workers eagerly, so their RPHs "
933 "can still be running.";
935 // Should not be able to find it.
937 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
939 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO
,
941 embedded_test_server()->GetURL("/service_worker/empty.html"),
943 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
, status
);
947 } // namespace content