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/single_thread_task_runner.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "content/browser/fileapi/chrome_blob_storage_context.h"
13 #include "content/browser/service_worker/embedded_worker_instance.h"
14 #include "content/browser/service_worker/embedded_worker_registry.h"
15 #include "content/browser/service_worker/service_worker_context_core.h"
16 #include "content/browser/service_worker/service_worker_context_observer.h"
17 #include "content/browser/service_worker/service_worker_context_wrapper.h"
18 #include "content/browser/service_worker/service_worker_registration.h"
19 #include "content/browser/service_worker/service_worker_test_utils.h"
20 #include "content/browser/service_worker/service_worker_version.h"
21 #include "content/common/service_worker/service_worker_messages.h"
22 #include "content/common/service_worker/service_worker_status_code.h"
23 #include "content/common/service_worker/service_worker_types.h"
24 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/navigation_entry.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/storage_partition.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/common/referrer.h"
32 #include "content/public/common/security_style.h"
33 #include "content/public/common/ssl_status.h"
34 #include "content/public/test/browser_test_utils.h"
35 #include "content/public/test/content_browser_test.h"
36 #include "content/public/test/content_browser_test_utils.h"
37 #include "content/shell/browser/shell.h"
38 #include "content/shell/browser/shell_content_browser_client.h"
39 #include "net/test/embedded_test_server/embedded_test_server.h"
40 #include "net/test/embedded_test_server/http_request.h"
41 #include "net/test/embedded_test_server/http_response.h"
42 #include "net/url_request/url_request_filter.h"
43 #include "net/url_request/url_request_interceptor.h"
44 #include "net/url_request/url_request_test_job.h"
45 #include "storage/browser/blob/blob_data_handle.h"
46 #include "storage/browser/blob/blob_data_snapshot.h"
47 #include "storage/browser/blob/blob_storage_context.h"
54 ServiceWorkerStatusCode status
;
55 ServiceWorkerFetchEventResult result
;
56 ServiceWorkerResponse response
;
57 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
60 void RunAndQuit(const base::Closure
& closure
,
61 const base::Closure
& quit
,
62 base::SingleThreadTaskRunner
* original_message_loop
) {
64 original_message_loop
->PostTask(FROM_HERE
, quit
);
67 void RunOnIOThreadWithDelay(const base::Closure
& closure
,
68 base::TimeDelta delay
) {
69 base::RunLoop run_loop
;
70 BrowserThread::PostDelayedTask(
73 base::Bind(&RunAndQuit
,
75 run_loop
.QuitClosure(),
76 base::ThreadTaskRunnerHandle::Get()),
81 void RunOnIOThread(const base::Closure
& closure
) {
82 RunOnIOThreadWithDelay(closure
, base::TimeDelta());
86 const base::Callback
<void(const base::Closure
& continuation
)>& closure
) {
87 base::RunLoop run_loop
;
88 base::Closure quit_on_original_thread
=
89 base::Bind(base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask
),
90 base::ThreadTaskRunnerHandle::Get().get(),
92 run_loop
.QuitClosure());
93 BrowserThread::PostTask(BrowserThread::IO
,
95 base::Bind(closure
, quit_on_original_thread
));
99 void ReceivePrepareResult(bool* is_prepared
) {
103 base::Closure
CreatePrepareReceiver(bool* is_prepared
) {
104 return base::Bind(&ReceivePrepareResult
, is_prepared
);
107 // Contrary to the style guide, the output parameter of this function comes
108 // before input parameters so Bind can be used on it to create a FetchCallback
109 // to pass to DispatchFetchEvent.
110 void ReceiveFetchResult(BrowserThread::ID run_quit_thread
,
111 const base::Closure
& quit
,
112 ChromeBlobStorageContext
* blob_context
,
113 FetchResult
* out_result
,
114 ServiceWorkerStatusCode actual_status
,
115 ServiceWorkerFetchEventResult actual_result
,
116 const ServiceWorkerResponse
& actual_response
) {
117 out_result
->status
= actual_status
;
118 out_result
->result
= actual_result
;
119 out_result
->response
= actual_response
;
120 if (!actual_response
.blob_uuid
.empty()) {
121 out_result
->blob_data_handle
=
122 blob_context
->context()->GetBlobDataFromUUID(
123 actual_response
.blob_uuid
);
126 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit
);
129 ServiceWorkerVersion::FetchCallback
CreateResponseReceiver(
130 BrowserThread::ID run_quit_thread
,
131 const base::Closure
& quit
,
132 ChromeBlobStorageContext
* blob_context
,
133 FetchResult
* result
) {
134 return base::Bind(&ReceiveFetchResult
, run_quit_thread
, quit
,
135 make_scoped_refptr
<ChromeBlobStorageContext
>(blob_context
),
139 void ReceiveFindRegistrationStatus(
140 BrowserThread::ID run_quit_thread
,
141 const base::Closure
& quit
,
142 ServiceWorkerStatusCode
* out_status
,
143 ServiceWorkerStatusCode status
,
144 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
145 *out_status
= status
;
147 BrowserThread::PostTask(run_quit_thread
, FROM_HERE
, quit
);
150 ServiceWorkerStorage::FindRegistrationCallback
CreateFindRegistrationReceiver(
151 BrowserThread::ID run_quit_thread
,
152 const base::Closure
& quit
,
153 ServiceWorkerStatusCode
* status
) {
154 return base::Bind(&ReceiveFindRegistrationStatus
, run_quit_thread
, quit
,
158 void ReadResponseBody(std::string
* body
,
159 storage::BlobDataHandle
* blob_data_handle
) {
160 ASSERT_TRUE(blob_data_handle
);
161 scoped_ptr
<storage::BlobDataSnapshot
> data
=
162 blob_data_handle
->CreateSnapshot();
163 ASSERT_EQ(1U, data
->items().size());
164 *body
= std::string(data
->items()[0]->bytes(), data
->items()[0]->length());
167 void ExpectResultAndRun(bool expected
,
168 const base::Closure
& continuation
,
170 EXPECT_EQ(expected
, actual
);
174 SyncRegistrationPtr
CreateOneShotSyncRegistration(const std::string
& tag
) {
175 SyncRegistrationPtr registration
= SyncRegistration::New();
176 registration
->tag
= tag
;
177 return registration
.Pass();
180 class WorkerActivatedObserver
181 : public ServiceWorkerContextObserver
,
182 public base::RefCountedThreadSafe
<WorkerActivatedObserver
> {
184 explicit WorkerActivatedObserver(ServiceWorkerContextWrapper
* context
)
185 : context_(context
) {}
187 RunOnIOThread(base::Bind(&WorkerActivatedObserver::InitOnIOThread
, this));
189 // ServiceWorkerContextObserver overrides.
190 void OnVersionStateChanged(int64 version_id
,
191 ServiceWorkerVersion::Status
) override
{
192 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
193 const ServiceWorkerVersion
* version
= context_
->GetLiveVersion(version_id
);
194 if (version
->status() == ServiceWorkerVersion::ACTIVATED
) {
195 context_
->RemoveObserver(this);
196 BrowserThread::PostTask(BrowserThread::UI
,
198 base::Bind(&WorkerActivatedObserver::Quit
, this));
201 void Wait() { run_loop_
.Run(); }
204 friend class base::RefCountedThreadSafe
<WorkerActivatedObserver
>;
205 ~WorkerActivatedObserver() override
{}
206 void InitOnIOThread() { context_
->AddObserver(this); }
207 void Quit() { run_loop_
.Quit(); }
209 base::RunLoop run_loop_
;
210 ServiceWorkerContextWrapper
* context_
;
211 DISALLOW_COPY_AND_ASSIGN(WorkerActivatedObserver
);
214 scoped_ptr
<net::test_server::HttpResponse
> VerifyServiceWorkerHeaderInRequest(
215 const net::test_server::HttpRequest
& request
) {
216 EXPECT_EQ(request
.relative_url
, "/service_worker/generated_sw.js");
217 std::map
<std::string
, std::string
>::const_iterator it
=
218 request
.headers
.find("Service-Worker");
219 EXPECT_TRUE(it
!= request
.headers
.end());
220 EXPECT_EQ("script", it
->second
);
222 scoped_ptr
<net::test_server::BasicHttpResponse
> http_response(
223 new net::test_server::BasicHttpResponse());
224 http_response
->set_content_type("text/javascript");
225 return http_response
.Pass();
228 // The ImportsBustMemcache test requires that the imported script
229 // would naturally be cached in blink's memcache, but the embedded
230 // test server doesn't produce headers that allow the blink's memcache
231 // to do that. This interceptor injects headers that give the import
232 // an experiration far in the future.
233 class LongLivedResourceInterceptor
: public net::URLRequestInterceptor
{
235 LongLivedResourceInterceptor(const std::string
& body
)
237 ~LongLivedResourceInterceptor() override
{}
239 // net::URLRequestInterceptor implementation
240 net::URLRequestJob
* MaybeInterceptRequest(
241 net::URLRequest
* request
,
242 net::NetworkDelegate
* network_delegate
) const override
{
243 const char kHeaders
[] =
245 "Content-Type: text/javascript\0"
246 "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
248 std::string
headers(kHeaders
, arraysize(kHeaders
));
249 return new net::URLRequestTestJob(
250 request
, network_delegate
, headers
, body_
, true);
255 DISALLOW_COPY_AND_ASSIGN(LongLivedResourceInterceptor
);
258 void CreateLongLivedResourceInterceptors(
259 const GURL
& worker_url
, const GURL
& import_url
) {
260 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
261 scoped_ptr
<net::URLRequestInterceptor
> interceptor
;
263 interceptor
.reset(new LongLivedResourceInterceptor(
264 "importScripts('long_lived_import.js');"));
265 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
266 worker_url
, interceptor
.Pass());
268 interceptor
.reset(new LongLivedResourceInterceptor(
269 "// the imported script does nothing"));
270 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
271 import_url
, interceptor
.Pass());
274 void CountScriptResources(
275 ServiceWorkerContextWrapper
* wrapper
,
277 int* num_resources
) {
280 std::vector
<ServiceWorkerRegistrationInfo
> infos
=
281 wrapper
->GetAllLiveRegistrationInfo();
286 size_t index
= infos
.size() - 1;
287 if (infos
[index
].installing_version
.version_id
!=
288 kInvalidServiceWorkerVersionId
)
289 version_id
= infos
[index
].installing_version
.version_id
;
290 else if (infos
[index
].waiting_version
.version_id
!=
291 kInvalidServiceWorkerVersionId
)
292 version_id
= infos
[1].waiting_version
.version_id
;
293 else if (infos
[index
].active_version
.version_id
!=
294 kInvalidServiceWorkerVersionId
)
295 version_id
= infos
[index
].active_version
.version_id
;
299 ServiceWorkerVersion
* version
= wrapper
->GetLiveVersion(version_id
);
300 *num_resources
= static_cast<int>(version
->script_cache_map()->size());
305 class ServiceWorkerBrowserTest
: public ContentBrowserTest
{
307 using self
= ServiceWorkerBrowserTest
;
309 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
310 command_line
->AppendSwitch(
311 switches::kEnableExperimentalWebPlatformFeatures
);
314 void SetUpOnMainThread() override
{
315 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
316 StoragePartition
* partition
= BrowserContext::GetDefaultStoragePartition(
317 shell()->web_contents()->GetBrowserContext());
318 wrapper_
= static_cast<ServiceWorkerContextWrapper
*>(
319 partition
->GetServiceWorkerContext());
321 // Navigate to the page to set up a renderer page (where we can embed
323 NavigateToURLBlockUntilNavigationsComplete(
325 embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
327 RunOnIOThread(base::Bind(&self::SetUpOnIOThread
, this));
330 void TearDownOnMainThread() override
{
331 RunOnIOThread(base::Bind(&self::TearDownOnIOThread
, this));
335 virtual void SetUpOnIOThread() {}
336 virtual void TearDownOnIOThread() {}
338 ServiceWorkerContextWrapper
* wrapper() { return wrapper_
.get(); }
339 ServiceWorkerContext
* public_context() { return wrapper(); }
341 void AssociateRendererProcessToPattern(const GURL
& pattern
) {
342 wrapper_
->process_manager()->AddProcessReferenceToPattern(
343 pattern
, shell()->web_contents()->GetRenderProcessHost()->GetID());
347 scoped_refptr
<ServiceWorkerContextWrapper
> wrapper_
;
350 class EmbeddedWorkerBrowserTest
: public ServiceWorkerBrowserTest
,
351 public EmbeddedWorkerInstance::Listener
{
353 using self
= EmbeddedWorkerBrowserTest
;
355 EmbeddedWorkerBrowserTest()
356 : last_worker_status_(EmbeddedWorkerInstance::STOPPED
) {}
357 ~EmbeddedWorkerBrowserTest() override
{}
359 void TearDownOnIOThread() override
{
361 worker_
->RemoveListener(this);
362 if (worker_
->status() == EmbeddedWorkerInstance::STARTING
||
363 worker_
->status() == EmbeddedWorkerInstance::RUNNING
) {
370 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
371 ServiceWorkerBrowserTest::SetUpCommandLine(command_line
);
373 // Code caching requires a bit more infrastructure that we don't care
374 // about in this test.
375 command_line
->AppendSwitchASCII(switches::kV8CacheOptions
, "none");
378 void StartOnIOThread() {
379 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
380 worker_
= wrapper()->context()->embedded_worker_registry()->CreateWorker();
381 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED
, worker_
->status());
382 worker_
->AddListener(this);
384 const int64 service_worker_version_id
= 33L;
385 const GURL pattern
= embedded_test_server()->GetURL("/");
386 const GURL script_url
= embedded_test_server()->GetURL(
387 "/service_worker/worker.js");
388 AssociateRendererProcessToPattern(pattern
);
389 int process_id
= shell()->web_contents()->GetRenderProcessHost()->GetID();
390 wrapper()->process_manager()->AddProcessReferenceToPattern(
391 pattern
, process_id
);
393 service_worker_version_id
,
396 base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2
, this));
399 void StartOnIOThread2(ServiceWorkerStatusCode status
) {
400 last_worker_status_
= worker_
->status();
401 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
402 EXPECT_EQ(EmbeddedWorkerInstance::STARTING
, last_worker_status_
);
404 if (status
!= SERVICE_WORKER_OK
&& !done_closure_
.is_null())
408 void StopOnIOThread() {
409 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
410 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING
, worker_
->status());
412 ServiceWorkerStatusCode status
= worker_
->Stop();
414 last_worker_status_
= worker_
->status();
415 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
416 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING
, last_worker_status_
);
418 if (status
!= SERVICE_WORKER_OK
&& !done_closure_
.is_null())
423 // EmbeddedWorkerInstance::Observer overrides:
424 void OnStarted() override
{
425 ASSERT_TRUE(worker_
!= NULL
);
426 ASSERT_FALSE(done_closure_
.is_null());
427 last_worker_status_
= worker_
->status();
428 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, done_closure_
);
430 void OnStopped(EmbeddedWorkerInstance::Status old_status
) override
{
431 ASSERT_TRUE(worker_
!= NULL
);
432 ASSERT_FALSE(done_closure_
.is_null());
433 last_worker_status_
= worker_
->status();
434 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, done_closure_
);
436 void OnReportException(const base::string16
& error_message
,
439 const GURL
& source_url
) override
{}
440 void OnReportConsoleMessage(int source_identifier
,
442 const base::string16
& message
,
444 const GURL
& source_url
) override
{}
445 bool OnMessageReceived(const IPC::Message
& message
) override
{ return false; }
447 scoped_ptr
<EmbeddedWorkerInstance
> worker_
;
448 EmbeddedWorkerInstance::Status last_worker_status_
;
450 // Called by EmbeddedWorkerInstance::Observer overrides so that
451 // test code can wait for the worker status notifications.
452 base::Closure done_closure_
;
455 class ConsoleListener
: public EmbeddedWorkerInstance::Listener
{
457 void OnReportConsoleMessage(int source_identifier
,
459 const base::string16
& message
,
461 const GURL
& source_url
) override
{
462 messages_
.push_back(message
);
463 if (!quit_
.is_null() && messages_
.size() == expected_message_count_
) {
464 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_
);
469 void WaitForConsoleMessages(size_t expected_message_count
) {
470 if (messages_
.size() >= expected_message_count
)
473 expected_message_count_
= expected_message_count
;
474 base::RunLoop console_run_loop
;
475 quit_
= console_run_loop
.QuitClosure();
476 console_run_loop
.Run();
478 ASSERT_EQ(messages_
.size(), expected_message_count
);
481 bool OnMessageReceived(const IPC::Message
& message
) override
{ return false; }
482 const std::vector
<base::string16
>& messages() const { return messages_
; }
485 std::vector
<base::string16
> messages_
;
486 size_t expected_message_count_
;
490 class ServiceWorkerVersionBrowserTest
: public ServiceWorkerBrowserTest
{
492 using self
= ServiceWorkerVersionBrowserTest
;
494 ~ServiceWorkerVersionBrowserTest() override
{}
496 void TearDownOnIOThread() override
{
497 registration_
= NULL
;
501 void InstallTestHelper(const std::string
& worker_url
,
502 ServiceWorkerStatusCode expected_status
) {
503 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
506 // Dispatch install on a worker.
507 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
508 base::RunLoop install_run_loop
;
509 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
510 base::Bind(&self::InstallOnIOThread
, this,
511 install_run_loop
.QuitClosure(),
513 install_run_loop
.Run();
514 ASSERT_EQ(expected_status
, status
);
517 status
= SERVICE_WORKER_ERROR_FAILED
;
518 base::RunLoop stop_run_loop
;
519 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
520 base::Bind(&self::StopOnIOThread
, this,
521 stop_run_loop
.QuitClosure(),
524 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
527 void ActivateTestHelper(
528 const std::string
& worker_url
,
529 ServiceWorkerStatusCode expected_status
) {
531 base::Bind(&self::SetUpRegistrationOnIOThread
, this, worker_url
));
532 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
533 base::RunLoop run_loop
;
534 BrowserThread::PostTask(
538 &self::ActivateOnIOThread
, this, run_loop
.QuitClosure(), &status
));
540 ASSERT_EQ(expected_status
, status
);
543 base::string16
RunSyncTestWithConsoleOutput(
544 const std::string
& worker_url
,
545 ServiceWorkerStatusCode expected_status
) {
547 base::Bind(&self::SetUpRegistrationOnIOThread
, this, worker_url
));
548 return SyncOnRegisteredWorkerWithConsoleOutput(expected_status
);
551 void SyncOnRegisteredWorker(ServiceWorkerStatusCode expected_status
) {
552 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
553 base::RunLoop sync_run_loop
;
554 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
555 base::Bind(&self::SyncEventOnIOThread
, this,
556 sync_run_loop
.QuitClosure(), &status
));
558 ASSERT_EQ(expected_status
, status
);
561 base::string16
SyncOnRegisteredWorkerWithConsoleOutput(
562 ServiceWorkerStatusCode expected_status
) {
563 ConsoleListener console_listener
;
564 version_
->embedded_worker()->AddListener(&console_listener
);
566 SyncOnRegisteredWorker(expected_status
);
568 console_listener
.WaitForConsoleMessages(1);
569 base::string16 console_output
= console_listener
.messages()[0];
570 version_
->embedded_worker()->RemoveListener(&console_listener
);
571 return console_output
;
574 void FetchOnRegisteredWorker(
575 ServiceWorkerFetchEventResult
* result
,
576 ServiceWorkerResponse
* response
,
577 scoped_ptr
<storage::BlobDataHandle
>* blob_data_handle
) {
578 blob_context_
= ChromeBlobStorageContext::GetFor(
579 shell()->web_contents()->GetBrowserContext());
580 bool prepare_result
= false;
581 FetchResult fetch_result
;
582 fetch_result
.status
= SERVICE_WORKER_ERROR_FAILED
;
583 base::RunLoop fetch_run_loop
;
584 BrowserThread::PostTask(BrowserThread::IO
,
586 base::Bind(&self::FetchOnIOThread
,
588 fetch_run_loop
.QuitClosure(),
591 fetch_run_loop
.Run();
592 ASSERT_TRUE(prepare_result
);
593 *result
= fetch_result
.result
;
594 *response
= fetch_result
.response
;
595 *blob_data_handle
= fetch_result
.blob_data_handle
.Pass();
596 ASSERT_EQ(SERVICE_WORKER_OK
, fetch_result
.status
);
599 void FetchTestHelper(const std::string
& worker_url
,
600 ServiceWorkerFetchEventResult
* result
,
601 ServiceWorkerResponse
* response
,
602 scoped_ptr
<storage::BlobDataHandle
>* blob_data_handle
) {
604 base::Bind(&self::SetUpRegistrationOnIOThread
, this, worker_url
));
605 FetchOnRegisteredWorker(result
, response
, blob_data_handle
);
608 void SetUpRegistrationOnIOThread(const std::string
& worker_url
) {
609 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
610 const GURL pattern
= embedded_test_server()->GetURL("/service_worker/");
611 registration_
= new ServiceWorkerRegistration(
613 wrapper()->context()->storage()->NewRegistrationId(),
614 wrapper()->context()->AsWeakPtr());
615 version_
= new ServiceWorkerVersion(
617 embedded_test_server()->GetURL(worker_url
),
618 wrapper()->context()->storage()->NewVersionId(),
619 wrapper()->context()->AsWeakPtr());
621 // Make the registration findable via storage functions.
622 wrapper()->context()->storage()->NotifyInstallingRegistration(
623 registration_
.get());
625 AssociateRendererProcessToPattern(pattern
);
628 void TimeoutWorkerOnIOThread() {
629 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
630 version_
->SimulatePingTimeoutForTesting();
633 void AddControlleeOnIOThread() {
634 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
635 scoped_ptr
<ServiceWorkerProviderHost
> host(new ServiceWorkerProviderHost(
636 33 /* dummy render process id */,
637 MSG_ROUTING_NONE
/* render_frame_id */, 1 /* dummy provider_id */,
638 SERVICE_WORKER_PROVIDER_FOR_WINDOW
, wrapper()->context()->AsWeakPtr(),
640 host
->SetDocumentUrl(
641 embedded_test_server()->GetURL("/service_worker/host"));
642 host
->AssociateRegistration(registration_
.get(),
643 false /* notify_controllerchange */);
644 wrapper()->context()->AddProviderHost(host
.Pass());
647 void AddWaitingWorkerOnIOThread(const std::string
& worker_url
) {
648 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
649 scoped_refptr
<ServiceWorkerVersion
> waiting_version(
650 new ServiceWorkerVersion(
651 registration_
.get(), embedded_test_server()->GetURL(worker_url
),
652 wrapper()->context()->storage()->NewVersionId(),
653 wrapper()->context()->AsWeakPtr()));
654 waiting_version
->SetStatus(ServiceWorkerVersion::INSTALLED
);
655 registration_
->SetWaitingVersion(waiting_version
.get());
656 registration_
->ActivateWaitingVersionWhenReady();
659 void StartWorker(ServiceWorkerStatusCode expected_status
) {
660 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI
));
661 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
662 base::RunLoop start_run_loop
;
663 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
664 base::Bind(&self::StartOnIOThread
, this,
665 start_run_loop
.QuitClosure(),
667 start_run_loop
.Run();
668 ASSERT_EQ(expected_status
, status
);
671 void StopWorker(ServiceWorkerStatusCode expected_status
) {
672 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI
));
673 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
674 base::RunLoop stop_run_loop
;
675 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
676 base::Bind(&self::StopOnIOThread
, this,
677 stop_run_loop
.QuitClosure(),
680 ASSERT_EQ(expected_status
, status
);
683 void StoreRegistration(int64 version_id
,
684 ServiceWorkerStatusCode expected_status
) {
685 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI
));
686 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
687 base::RunLoop store_run_loop
;
688 BrowserThread::PostTask(
689 BrowserThread::IO
, FROM_HERE
,
690 base::Bind(&self::StoreOnIOThread
, this, store_run_loop
.QuitClosure(),
691 &status
, version_id
));
692 store_run_loop
.Run();
693 ASSERT_EQ(expected_status
, status
);
695 RunOnIOThread(base::Bind(&self::NotifyDoneInstallingRegistrationOnIOThread
,
699 void FindRegistrationForId(int64 id
,
701 ServiceWorkerStatusCode expected_status
) {
702 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI
));
703 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
704 base::RunLoop run_loop
;
705 BrowserThread::PostTask(
706 BrowserThread::IO
, FROM_HERE
,
707 base::Bind(&self::FindRegistrationForIdOnIOThread
, this,
708 run_loop
.QuitClosure(), &status
, id
, origin
));
710 ASSERT_EQ(expected_status
, status
);
713 void FindRegistrationForIdOnIOThread(const base::Closure
& done
,
714 ServiceWorkerStatusCode
* result
,
716 const GURL
& origin
) {
717 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
718 wrapper()->context()->storage()->FindRegistrationForId(
720 CreateFindRegistrationReceiver(BrowserThread::UI
, done
, result
));
723 void NotifyDoneInstallingRegistrationOnIOThread(
724 ServiceWorkerStatusCode status
) {
725 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
726 wrapper()->context()->storage()->NotifyDoneInstallingRegistration(
727 registration_
.get(), version_
.get(), status
);
730 void RemoveLiveRegistrationOnIOThread(int64 id
) {
731 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
732 wrapper()->context()->RemoveLiveRegistration(id
);
735 void StartOnIOThread(const base::Closure
& done
,
736 ServiceWorkerStatusCode
* result
) {
737 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
738 version_
->StartWorker(CreateReceiver(BrowserThread::UI
, done
, result
));
741 void InstallOnIOThread(const base::Closure
& done
,
742 ServiceWorkerStatusCode
* result
) {
743 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
744 version_
->SetStatus(ServiceWorkerVersion::INSTALLING
);
745 version_
->DispatchInstallEvent(
746 CreateReceiver(BrowserThread::UI
, done
, result
));
749 void StoreOnIOThread(const base::Closure
& done
,
750 ServiceWorkerStatusCode
* result
,
752 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
753 ServiceWorkerVersion
* version
=
754 wrapper()->context()->GetLiveVersion(version_id
);
755 wrapper()->context()->storage()->StoreRegistration(
756 registration_
.get(), version
,
757 CreateReceiver(BrowserThread::UI
, done
, result
));
760 void ActivateOnIOThread(const base::Closure
& done
,
761 ServiceWorkerStatusCode
* result
) {
762 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
763 version_
->SetStatus(ServiceWorkerVersion::ACTIVATING
);
764 registration_
->SetActiveVersion(version_
.get());
765 version_
->DispatchActivateEvent(
766 CreateReceiver(BrowserThread::UI
, done
, result
));
769 void FetchOnIOThread(const base::Closure
& done
,
770 bool* prepare_result
,
771 FetchResult
* result
) {
772 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
773 ServiceWorkerFetchRequest
request(
774 embedded_test_server()->GetURL("/service_worker/empty.html"),
776 ServiceWorkerHeaderMap(),
779 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
780 version_
->DispatchFetchEvent(
782 CreatePrepareReceiver(prepare_result
),
783 CreateResponseReceiver(
784 BrowserThread::UI
, done
, blob_context_
.get(), result
));
787 void StopOnIOThread(const base::Closure
& done
,
788 ServiceWorkerStatusCode
* result
) {
789 ASSERT_TRUE(version_
.get());
790 version_
->StopWorker(CreateReceiver(BrowserThread::UI
, done
, result
));
793 void SyncEventOnIOThread(const base::Closure
& done
,
794 ServiceWorkerStatusCode
* result
) {
795 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
796 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
797 version_
->DispatchSyncEvent(
798 CreateOneShotSyncRegistration(""),
799 CreateReceiver(BrowserThread::UI
, done
, result
));
803 scoped_refptr
<ServiceWorkerRegistration
> registration_
;
804 scoped_refptr
<ServiceWorkerVersion
> version_
;
805 scoped_refptr
<ChromeBlobStorageContext
> blob_context_
;
808 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest
, StartAndStop
) {
809 // Start a worker and wait until OnStarted() is called.
810 base::RunLoop start_run_loop
;
811 done_closure_
= start_run_loop
.QuitClosure();
812 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
813 base::Bind(&self::StartOnIOThread
, this));
814 start_run_loop
.Run();
816 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING
, last_worker_status_
);
818 // Stop a worker and wait until OnStopped() is called.
819 base::RunLoop stop_run_loop
;
820 done_closure_
= stop_run_loop
.QuitClosure();
821 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
822 base::Bind(&self::StopOnIOThread
, this));
825 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED
, last_worker_status_
);
828 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, StartAndStop
) {
829 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
830 "/service_worker/worker.js"));
833 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
834 base::RunLoop start_run_loop
;
835 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
836 base::Bind(&self::StartOnIOThread
, this,
837 start_run_loop
.QuitClosure(),
839 start_run_loop
.Run();
840 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
843 status
= SERVICE_WORKER_ERROR_FAILED
;
844 base::RunLoop stop_run_loop
;
845 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
846 base::Bind(&self::StopOnIOThread
, this,
847 stop_run_loop
.QuitClosure(),
850 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
853 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, StartNotFound
) {
854 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
855 "/service_worker/nonexistent.js"));
857 // Start a worker for nonexistent URL.
858 StartWorker(SERVICE_WORKER_ERROR_NETWORK
);
861 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, ReadResourceFailure
) {
862 // Create a registration.
863 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
864 "/service_worker/worker.js"));
865 version_
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
867 // Add a non-existent resource to the version.
868 std::vector
<ServiceWorkerDatabase::ResourceRecord
> records
;
870 ServiceWorkerDatabase::ResourceRecord(30, version_
->script_url(), 100));
871 version_
->script_cache_map()->SetResources(records
);
873 // Store the registration.
874 StoreRegistration(version_
->version_id(), SERVICE_WORKER_OK
);
876 // Start the worker. We'll fail to read the resource.
877 StartWorker(SERVICE_WORKER_ERROR_DISK_CACHE
);
878 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
, version_
->status());
880 // The registration should be deleted from storage since the broken worker was
882 RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread
, this,
883 registration_
->id()));
884 FindRegistrationForId(registration_
->id(),
885 registration_
->pattern().GetOrigin(),
886 SERVICE_WORKER_ERROR_NOT_FOUND
);
889 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
890 ReadResourceFailure_WaitingWorker
) {
891 // Create a registration and active version.
892 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
893 "/service_worker/worker.js"));
894 base::RunLoop activate_run_loop
;
895 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
896 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
897 base::Bind(&self::ActivateOnIOThread
, this,
898 activate_run_loop
.QuitClosure(), &status
));
899 activate_run_loop
.Run();
900 EXPECT_EQ(SERVICE_WORKER_OK
, status
);
901 ASSERT_TRUE(registration_
->active_version());
903 // Give the version a controllee.
904 RunOnIOThread(base::Bind(&self::AddControlleeOnIOThread
, this));
906 // Add a non-existent resource to the version.
907 std::vector
<ServiceWorkerDatabase::ResourceRecord
> records
;
909 ServiceWorkerDatabase::ResourceRecord(30, version_
->script_url(), 100));
910 version_
->script_cache_map()->SetResources(records
);
912 // Make a waiting version and store it.
913 RunOnIOThread(base::Bind(&self::AddWaitingWorkerOnIOThread
, this,
914 "/service_worker/worker.js"));
915 registration_
->waiting_version()->script_cache_map()->SetResources(records
);
916 StoreRegistration(registration_
->waiting_version()->version_id(),
919 // Start the broken worker. We'll fail to read from disk and the worker should
921 StopWorker(SERVICE_WORKER_OK
); // in case it's already running
922 StartWorker(SERVICE_WORKER_ERROR_DISK_CACHE
);
923 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT
, version_
->status());
925 // The registration should still be in storage since the waiting worker was
927 RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread
, this,
928 registration_
->id()));
929 FindRegistrationForId(registration_
->id(),
930 registration_
->pattern().GetOrigin(),
934 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, Install
) {
935 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK
);
938 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
939 InstallWithWaitUntil_Fulfilled
) {
940 InstallTestHelper("/service_worker/worker_install_fulfilled.js",
944 // Check that ServiceWorker script requests set a "Service-Worker: script"
946 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
947 ServiceWorkerScriptHeader
) {
948 embedded_test_server()->RegisterRequestHandler(
949 base::Bind(&VerifyServiceWorkerHeaderInRequest
));
950 InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK
);
953 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
954 Activate_NoEventListener
) {
955 ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK
);
956 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING
, version_
->status());
959 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, Activate_Rejected
) {
960 ActivateTestHelper("/service_worker/worker_activate_rejected.js",
961 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
);
964 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
965 InstallWithWaitUntil_Rejected
) {
966 InstallTestHelper("/service_worker/worker_install_rejected.js",
967 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
);
970 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
971 InstallWithWaitUntil_RejectConsoleMessage
) {
972 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
973 "/service_worker/worker_install_rejected.js"));
975 ConsoleListener console_listener
;
976 version_
->embedded_worker()->AddListener(&console_listener
);
978 // Dispatch install on a worker.
979 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
980 base::RunLoop install_run_loop
;
981 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
982 base::Bind(&self::InstallOnIOThread
, this,
983 install_run_loop
.QuitClosure(), &status
));
984 install_run_loop
.Run();
985 ASSERT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
, status
);
987 const base::string16 expected
=
988 base::ASCIIToUTF16("Rejecting oninstall event");
989 console_listener
.WaitForConsoleMessages(1);
990 ASSERT_NE(base::string16::npos
,
991 console_listener
.messages()[0].find(expected
));
992 version_
->embedded_worker()->RemoveListener(&console_listener
);
995 class WaitForLoaded
: public EmbeddedWorkerInstance::Listener
{
997 WaitForLoaded(const base::Closure
& quit
) : quit_(quit
) {}
999 void OnScriptLoaded() override
{
1000 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_
);
1002 bool OnMessageReceived(const IPC::Message
& message
) override
{ return false; }
1005 base::Closure quit_
;
1008 // This test has started flaking somewhat consistently on Win, Mac and Linux.
1009 // Disabling for now, see http://crbug.com/496065.
1010 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
1011 DISABLED_TimeoutStartingWorker
) {
1012 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
1013 "/service_worker/while_true_worker.js"));
1015 // Start a worker, waiting until the script is loaded.
1016 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
1017 base::RunLoop start_run_loop
;
1018 base::RunLoop load_run_loop
;
1019 WaitForLoaded
wait_for_load(load_run_loop
.QuitClosure());
1020 version_
->embedded_worker()->AddListener(&wait_for_load
);
1021 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
1022 base::Bind(&self::StartOnIOThread
, this,
1023 start_run_loop
.QuitClosure(), &status
));
1024 load_run_loop
.Run();
1025 version_
->embedded_worker()->RemoveListener(&wait_for_load
);
1027 // The script has loaded but start has not completed yet.
1028 ASSERT_EQ(SERVICE_WORKER_ERROR_FAILED
, status
);
1029 EXPECT_EQ(ServiceWorkerVersion::STARTING
, version_
->running_status());
1031 // Simulate execution timeout. Use a delay to prevent killing the worker
1032 // before it's started execution.
1033 EXPECT_TRUE(version_
->timeout_timer_
.IsRunning());
1034 RunOnIOThreadWithDelay(base::Bind(&self::TimeoutWorkerOnIOThread
, this),
1035 base::TimeDelta::FromMilliseconds(100));
1036 start_run_loop
.Run();
1038 EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT
, status
);
1041 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, TimeoutWorkerInEvent
) {
1042 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
1043 "/service_worker/while_true_in_install_worker.js"));
1046 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
1047 base::RunLoop start_run_loop
;
1048 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
1049 base::Bind(&self::StartOnIOThread
, this,
1050 start_run_loop
.QuitClosure(), &status
));
1051 start_run_loop
.Run();
1052 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
1054 // Dispatch an event.
1055 base::RunLoop install_run_loop
;
1056 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
1057 base::Bind(&self::InstallOnIOThread
, this,
1058 install_run_loop
.QuitClosure(), &status
));
1060 // Simulate execution timeout. Use a delay to prevent killing the worker
1061 // before it's started execution.
1062 EXPECT_TRUE(version_
->timeout_timer_
.IsRunning());
1063 RunOnIOThreadWithDelay(base::Bind(&self::TimeoutWorkerOnIOThread
, this),
1064 base::TimeDelta::FromMilliseconds(100));
1065 install_run_loop
.Run();
1067 EXPECT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
, status
);
1070 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, FetchEvent_Response
) {
1071 ServiceWorkerFetchEventResult result
;
1072 ServiceWorkerResponse response
;
1073 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
1074 FetchTestHelper("/service_worker/fetch_event.js",
1075 &result
, &response
, &blob_data_handle
);
1076 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE
, result
);
1077 EXPECT_EQ(301, response
.status_code
);
1078 EXPECT_EQ("Moved Permanently", response
.status_text
);
1079 ServiceWorkerHeaderMap expected_headers
;
1080 expected_headers
["content-language"] = "fi";
1081 expected_headers
["content-type"] = "text/html; charset=UTF-8";
1082 EXPECT_EQ(expected_headers
, response
.headers
);
1086 base::Bind(&ReadResponseBody
,
1087 &body
, base::Owned(blob_data_handle
.release())));
1088 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body
);
1091 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
1092 FetchEvent_respondWithRejection
) {
1093 ServiceWorkerFetchEventResult result
;
1094 ServiceWorkerResponse response
;
1095 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
1097 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread
, this,
1098 "/service_worker/fetch_event_rejected.js"));
1100 ConsoleListener console_listener
;
1101 version_
->embedded_worker()->AddListener(&console_listener
);
1103 FetchOnRegisteredWorker(&result
, &response
, &blob_data_handle
);
1104 const base::string16 expected1
= base::ASCIIToUTF16(
1105 "resulted in a network error response: the promise was rejected.");
1106 const base::string16 expected2
=
1107 base::ASCIIToUTF16("Uncaught (in promise) Rejecting respondWith promise");
1108 console_listener
.WaitForConsoleMessages(2);
1109 ASSERT_NE(base::string16::npos
,
1110 console_listener
.messages()[0].find(expected1
));
1111 ASSERT_EQ(0u, console_listener
.messages()[1].find(expected2
));
1112 version_
->embedded_worker()->RemoveListener(&console_listener
);
1114 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE
, result
);
1115 EXPECT_EQ(0, response
.status_code
);
1117 ASSERT_FALSE(blob_data_handle
);
1120 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, SyncEventHandled
) {
1121 RunOnIOThread(base::Bind(
1122 &self::SetUpRegistrationOnIOThread
, this, "/service_worker/sync.js"));
1123 ServiceWorkerFetchEventResult result
;
1124 ServiceWorkerResponse response
;
1125 scoped_ptr
<storage::BlobDataHandle
> blob_data_handle
;
1126 // Should 404 before sync event.
1127 FetchOnRegisteredWorker(&result
, &response
, &blob_data_handle
);
1128 EXPECT_EQ(404, response
.status_code
);
1130 // Run the sync event.
1131 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
1132 base::RunLoop sync_run_loop
;
1133 BrowserThread::PostTask(BrowserThread::IO
,
1135 base::Bind(&self::SyncEventOnIOThread
,
1137 sync_run_loop
.QuitClosure(),
1139 sync_run_loop
.Run();
1140 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
1142 // Should 200 after sync event.
1143 FetchOnRegisteredWorker(&result
, &response
, &blob_data_handle
);
1144 EXPECT_EQ(200, response
.status_code
);
1147 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
, SyncEventInterface
) {
1148 // Verify that the fired sync event has the correct interface.
1149 // The js event handler will console.log the event properties.
1150 base::string16 console_output
= RunSyncTestWithConsoleOutput(
1151 "/background_sync/sync_event_interface.js", SERVICE_WORKER_OK
);
1153 EXPECT_FALSE(console_output
.empty());
1155 // Console output is a pipe-delimited string, as:
1156 // <event prototype>|<typeof waitUntil>
1157 std::vector
<base::string16
> event_properties
;
1158 base::SplitString(console_output
, '|', &event_properties
);
1160 const base::string16::size_type num_properties
= 2;
1161 const base::string16 event_type
= base::ASCIIToUTF16("SyncEvent");
1162 const base::string16 wait_until_type
= base::ASCIIToUTF16("function");
1163 EXPECT_EQ(num_properties
, event_properties
.size());
1164 EXPECT_EQ(event_type
, event_properties
[0]);
1165 EXPECT_EQ(wait_until_type
, event_properties
[1]);
1168 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
1169 SyncEventWaitUntil_Fulfilled
) {
1170 base::string16 console_output
= RunSyncTestWithConsoleOutput(
1171 "/background_sync/sync_event_fulfilled.js", SERVICE_WORKER_OK
);
1173 // Verify that the event.waitUntil function resolved the promise. If so,
1174 // the js event handler will console.log the expected output.
1175 const base::string16 expected
= base::ASCIIToUTF16("Fulfilling onsync event");
1176 EXPECT_EQ(expected
, console_output
);
1179 // https://crbug.com/504202
1180 #if defined(THREAD_SANITIZER)
1181 #define MAYBE_SyncEventWaitUntil_Rejected DISABLED_SyncEventWaitUntil_Rejected
1183 #define MAYBE_SyncEventWaitUntil_Rejected SyncEventWaitUntil_Rejected
1185 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest
,
1186 MAYBE_SyncEventWaitUntil_Rejected
) {
1187 base::string16 console_output
= RunSyncTestWithConsoleOutput(
1188 "/background_sync/sync_event_rejected.js",
1189 SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED
);
1191 // Verify that the event.waitUntil function rejected the promise. If so,
1192 // the js event handler will console.log the expected output.
1193 const base::string16 expected
= base::ASCIIToUTF16("Rejecting onsync event");
1194 EXPECT_EQ(expected
, console_output
);
1197 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
, Reload
) {
1198 const char kPageUrl
[] = "/service_worker/reload.html";
1199 const char kWorkerUrl
[] = "/service_worker/fetch_event_reload.js";
1200 scoped_refptr
<WorkerActivatedObserver
> observer
=
1201 new WorkerActivatedObserver(wrapper());
1203 public_context()->RegisterServiceWorker(
1204 embedded_test_server()->GetURL(kPageUrl
),
1205 embedded_test_server()->GetURL(kWorkerUrl
),
1206 base::Bind(&ExpectResultAndRun
, true, base::Bind(&base::DoNothing
)));
1209 const base::string16 title1
= base::ASCIIToUTF16("reload=false");
1210 TitleWatcher
title_watcher1(shell()->web_contents(), title1
);
1211 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl
));
1212 EXPECT_EQ(title1
, title_watcher1
.WaitAndGetTitle());
1214 const base::string16 title2
= base::ASCIIToUTF16("reload=true");
1215 TitleWatcher
title_watcher2(shell()->web_contents(), title2
);
1216 ReloadBlockUntilNavigationsComplete(shell(), 1);
1217 EXPECT_EQ(title2
, title_watcher2
.WaitAndGetTitle());
1221 base::RunLoop run_loop
;
1222 public_context()->UnregisterServiceWorker(
1223 embedded_test_server()->GetURL(kPageUrl
),
1224 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
1228 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
,
1229 ResponseFromHTTPSServiceWorkerIsMarkedAsSecure
) {
1230 const char kPageUrl
[] = "files/service_worker/fetch_event_blob.html";
1231 const char kWorkerUrl
[] = "files/service_worker/fetch_event_blob.js";
1232 net::SpawnedTestServer
https_server(
1233 net::SpawnedTestServer::TYPE_HTTPS
,
1234 net::BaseTestServer::SSLOptions(
1235 net::BaseTestServer::SSLOptions::CERT_OK
),
1236 base::FilePath(FILE_PATH_LITERAL("content/test/data/")));
1237 ASSERT_TRUE(https_server
.Start());
1239 scoped_refptr
<WorkerActivatedObserver
> observer
=
1240 new WorkerActivatedObserver(wrapper());
1242 public_context()->RegisterServiceWorker(
1243 https_server
.GetURL(kPageUrl
),
1244 https_server
.GetURL(kWorkerUrl
),
1245 base::Bind(&ExpectResultAndRun
, true, base::Bind(&base::DoNothing
)));
1248 const base::string16 title
= base::ASCIIToUTF16("Title");
1249 TitleWatcher
title_watcher(shell()->web_contents(), title
);
1250 NavigateToURL(shell(), https_server
.GetURL(kPageUrl
));
1251 EXPECT_EQ(title
, title_watcher
.WaitAndGetTitle());
1252 EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
1253 NavigationEntry
* entry
=
1254 shell()->web_contents()->GetController().GetVisibleEntry();
1255 EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED
, entry
->GetSSL().security_style
);
1259 base::RunLoop run_loop
;
1260 public_context()->UnregisterServiceWorker(
1261 https_server
.GetURL(kPageUrl
),
1262 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
1266 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
,
1267 ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure
) {
1268 const char kPageUrl
[] = "/service_worker/fetch_event_blob.html";
1269 const char kWorkerUrl
[] = "/service_worker/fetch_event_blob.js";
1270 scoped_refptr
<WorkerActivatedObserver
> observer
=
1271 new WorkerActivatedObserver(wrapper());
1273 public_context()->RegisterServiceWorker(
1274 embedded_test_server()->GetURL(kPageUrl
),
1275 embedded_test_server()->GetURL(kWorkerUrl
),
1276 base::Bind(&ExpectResultAndRun
, true, base::Bind(&base::DoNothing
)));
1279 const base::string16 title
= base::ASCIIToUTF16("Title");
1280 TitleWatcher
title_watcher(shell()->web_contents(), title
);
1281 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl
));
1282 EXPECT_EQ(title
, title_watcher
.WaitAndGetTitle());
1283 EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
1284 NavigationEntry
* entry
=
1285 shell()->web_contents()->GetController().GetVisibleEntry();
1286 EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED
, entry
->GetSSL().security_style
);
1290 base::RunLoop run_loop
;
1291 public_context()->UnregisterServiceWorker(
1292 embedded_test_server()->GetURL(kPageUrl
),
1293 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
1297 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
, ImportsBustMemcache
) {
1298 const char kScopeUrl
[] = "/service_worker/imports_bust_memcache_scope/";
1299 const char kPageUrl
[] = "/service_worker/imports_bust_memcache.html";
1300 const char kScriptUrl
[] = "/service_worker/worker_with_one_import.js";
1301 const char kImportUrl
[] = "/service_worker/long_lived_import.js";
1302 const base::string16
kOKTitle(base::ASCIIToUTF16("OK"));
1303 const base::string16
kFailTitle(base::ASCIIToUTF16("FAIL"));
1306 base::Bind(&CreateLongLivedResourceInterceptors
,
1307 embedded_test_server()->GetURL(kScriptUrl
),
1308 embedded_test_server()->GetURL(kImportUrl
)));
1310 TitleWatcher
title_watcher(shell()->web_contents(), kOKTitle
);
1311 title_watcher
.AlsoWaitForTitle(kFailTitle
);
1312 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl
));
1313 base::string16 title
= title_watcher
.WaitAndGetTitle();
1314 EXPECT_EQ(kOKTitle
, title
);
1316 // Verify the number of resources in the implicit script cache is correct.
1317 const int kExpectedNumResources
= 2;
1318 int num_resources
= 0;
1320 base::Bind(&CountScriptResources
,
1321 base::Unretained(wrapper()),
1322 embedded_test_server()->GetURL(kScopeUrl
),
1324 EXPECT_EQ(kExpectedNumResources
, num_resources
);
1327 class ServiceWorkerBlackBoxBrowserTest
: public ServiceWorkerBrowserTest
{
1329 using self
= ServiceWorkerBlackBoxBrowserTest
;
1331 void FindRegistrationOnIO(const GURL
& document_url
,
1332 ServiceWorkerStatusCode
* status
,
1333 const base::Closure
& continuation
) {
1334 wrapper()->FindRegistrationForDocument(
1336 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2
,
1337 this, status
, continuation
));
1340 void FindRegistrationOnIO2(
1341 ServiceWorkerStatusCode
* out_status
,
1342 const base::Closure
& continuation
,
1343 ServiceWorkerStatusCode status
,
1344 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
1345 *out_status
= status
;
1346 if (!registration
.get())
1347 EXPECT_NE(SERVICE_WORKER_OK
, status
);
1352 static int CountRenderProcessHosts() {
1354 for (RenderProcessHost::iterator
iter(RenderProcessHost::AllHostsIterator());
1362 // Flaky timeouts on CrOS: http://crbug.com/387045
1363 #if defined(OS_CHROMEOS)
1364 #define MAYBE_Registration DISABLED_Registration
1366 #define MAYBE_Registration Registration
1368 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest
, MAYBE_Registration
) {
1369 // Close the only window to be sure we're not re-using its RenderProcessHost.
1371 EXPECT_EQ(0, CountRenderProcessHosts());
1373 const char kWorkerUrl
[] = "/service_worker/fetch_event.js";
1374 const char kScope
[] = "/service_worker/";
1376 // Unregistering nothing should return false.
1378 base::RunLoop run_loop
;
1379 public_context()->UnregisterServiceWorker(
1380 embedded_test_server()->GetURL("/"),
1381 base::Bind(&ExpectResultAndRun
, false, run_loop
.QuitClosure()));
1385 // If we use a worker URL that doesn't exist, registration fails.
1387 base::RunLoop run_loop
;
1388 public_context()->RegisterServiceWorker(
1389 embedded_test_server()->GetURL(kScope
),
1390 embedded_test_server()->GetURL("/does/not/exist"),
1391 base::Bind(&ExpectResultAndRun
, false, run_loop
.QuitClosure()));
1394 EXPECT_EQ(0, CountRenderProcessHosts());
1396 // Register returns when the promise would be resolved.
1398 base::RunLoop run_loop
;
1399 public_context()->RegisterServiceWorker(
1400 embedded_test_server()->GetURL(kScope
),
1401 embedded_test_server()->GetURL(kWorkerUrl
),
1402 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
1405 EXPECT_EQ(1, CountRenderProcessHosts());
1407 // Registering again should succeed, although the algo still
1408 // might not be complete.
1410 base::RunLoop run_loop
;
1411 public_context()->RegisterServiceWorker(
1412 embedded_test_server()->GetURL(kScope
),
1413 embedded_test_server()->GetURL(kWorkerUrl
),
1414 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
1418 // The registration algo might not be far enough along to have
1419 // stored the registration data, so it may not be findable
1422 // Unregistering something should return true.
1424 base::RunLoop run_loop
;
1425 public_context()->UnregisterServiceWorker(
1426 embedded_test_server()->GetURL(kScope
),
1427 base::Bind(&ExpectResultAndRun
, true, run_loop
.QuitClosure()));
1430 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
1431 "workers eagerly, so their RPHs "
1432 "can still be running.";
1434 // Should not be able to find it.
1436 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
1438 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO
,
1440 embedded_test_server()->GetURL("/service_worker/empty.html"),
1442 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND
, status
);
1446 #if defined(ANDROID)
1447 #define MAYBE_CrossSiteTransfer DISABLED_CrossSiteTransfer
1449 #define MAYBE_CrossSiteTransfer CrossSiteTransfer
1451 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest
, MAYBE_CrossSiteTransfer
) {
1452 // The first page registers a service worker.
1453 const char kRegisterPageUrl
[] = "/service_worker/cross_site_xfer.html";
1454 const base::string16
kOKTitle1(base::ASCIIToUTF16("OK_1"));
1455 const base::string16
kFailTitle1(base::ASCIIToUTF16("FAIL_1"));
1456 content::TitleWatcher
title_watcher1(shell()->web_contents(), kOKTitle1
);
1457 title_watcher1
.AlsoWaitForTitle(kFailTitle1
);
1459 NavigateToURL(shell(), embedded_test_server()->GetURL(kRegisterPageUrl
));
1460 ASSERT_EQ(kOKTitle1
, title_watcher1
.WaitAndGetTitle());
1462 // Force process swapping behavior.
1463 ShellContentBrowserClient::SetSwapProcessesForRedirect(true);
1465 // The second pages loads via the serviceworker including a subresource.
1466 const char kConfirmPageUrl
[] =
1467 "/service_worker/cross_site_xfer_scope/"
1468 "cross_site_xfer_confirm_via_serviceworker.html";
1469 const base::string16
kOKTitle2(base::ASCIIToUTF16("OK_2"));
1470 const base::string16
kFailTitle2(base::ASCIIToUTF16("FAIL_2"));
1471 content::TitleWatcher
title_watcher2(shell()->web_contents(), kOKTitle2
);
1472 title_watcher2
.AlsoWaitForTitle(kFailTitle2
);
1474 NavigateToURL(shell(), embedded_test_server()->GetURL(kConfirmPageUrl
));
1475 EXPECT_EQ(kOKTitle2
, title_watcher2
.WaitAndGetTitle());
1478 class ServiceWorkerVersionBrowserV8CacheTest
1479 : public ServiceWorkerVersionBrowserTest
,
1480 public ServiceWorkerVersion::Listener
{
1482 using self
= ServiceWorkerVersionBrowserV8CacheTest
;
1483 ~ServiceWorkerVersionBrowserV8CacheTest() override
{
1485 version_
->RemoveListener(this);
1487 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
1488 ServiceWorkerBrowserTest::SetUpCommandLine(command_line
);
1489 command_line
->AppendSwitchASCII(switches::kV8CacheOptions
, "code");
1491 void SetUpRegistrationAndListenerOnIOThread(const std::string
& worker_url
) {
1492 SetUpRegistrationOnIOThread(worker_url
);
1493 version_
->AddListener(this);
1497 // ServiceWorkerVersion::Listener overrides
1498 void OnCachedMetadataUpdated(ServiceWorkerVersion
* version
) override
{
1499 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
1500 cache_updated_closure_
);
1503 base::Closure cache_updated_closure_
;
1506 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserV8CacheTest
, Restart
) {
1507 RunOnIOThread(base::Bind(&self::SetUpRegistrationAndListenerOnIOThread
, this,
1508 "/service_worker/worker.js"));
1510 base::RunLoop cached_metadata_run_loop
;
1511 cache_updated_closure_
= cached_metadata_run_loop
.QuitClosure();
1514 StartWorker(SERVICE_WORKER_OK
);
1516 // Wait for the matadata is stored. This run loop should finish when
1517 // OnCachedMetadataUpdated() is called.
1518 cached_metadata_run_loop
.Run();
1520 // Activate the worker.
1521 ServiceWorkerStatusCode status
= SERVICE_WORKER_ERROR_FAILED
;
1522 base::RunLoop activate_run_loop
;
1523 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
1524 base::Bind(&self::ActivateOnIOThread
, this,
1525 activate_run_loop
.QuitClosure(), &status
));
1526 activate_run_loop
.Run();
1527 ASSERT_EQ(SERVICE_WORKER_OK
, status
);
1529 StopWorker(SERVICE_WORKER_OK
);
1530 // Restart the worker.
1531 StartWorker(SERVICE_WORKER_OK
);
1533 StopWorker(SERVICE_WORKER_OK
);
1536 } // namespace content