Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_browsertest.cc
blobca70f778c22a8f2575c60bd063ef7a41c164c047
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.
5 #include "base/bind.h"
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"
49 namespace content {
51 namespace {
53 struct FetchResult {
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) {
63 closure.Run();
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(
71 BrowserThread::IO,
72 FROM_HERE,
73 base::Bind(&RunAndQuit,
74 closure,
75 run_loop.QuitClosure(),
76 base::ThreadTaskRunnerHandle::Get()),
77 delay);
78 run_loop.Run();
81 void RunOnIOThread(const base::Closure& closure) {
82 RunOnIOThreadWithDelay(closure, base::TimeDelta());
85 void RunOnIOThread(
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(),
91 FROM_HERE,
92 run_loop.QuitClosure());
93 BrowserThread::PostTask(BrowserThread::IO,
94 FROM_HERE,
95 base::Bind(closure, quit_on_original_thread));
96 run_loop.Run();
99 void ReceivePrepareResult(bool* is_prepared) {
100 *is_prepared = true;
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);
125 if (!quit.is_null())
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),
136 result);
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;
146 if (!quit.is_null())
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,
155 status);
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,
169 bool actual) {
170 EXPECT_EQ(expected, actual);
171 continuation.Run();
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> {
183 public:
184 explicit WorkerActivatedObserver(ServiceWorkerContextWrapper* context)
185 : context_(context) {}
186 void Init() {
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,
197 FROM_HERE,
198 base::Bind(&WorkerActivatedObserver::Quit, this));
201 void Wait() { run_loop_.Run(); }
203 private:
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 {
234 public:
235 LongLivedResourceInterceptor(const std::string& body)
236 : body_(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[] =
244 "HTTP/1.1 200 OK\0"
245 "Content-Type: text/javascript\0"
246 "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
247 "\0";
248 std::string headers(kHeaders, arraysize(kHeaders));
249 return new net::URLRequestTestJob(
250 request, network_delegate, headers, body_, true);
253 private:
254 std::string body_;
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,
276 const GURL& scope,
277 int* num_resources) {
278 *num_resources = -1;
280 std::vector<ServiceWorkerRegistrationInfo> infos =
281 wrapper->GetAllLiveRegistrationInfo();
282 if (infos.empty())
283 return;
285 int version_id;
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;
296 else
297 return;
299 ServiceWorkerVersion* version = wrapper->GetLiveVersion(version_id);
300 *num_resources = static_cast<int>(version->script_cache_map()->size());
303 } // namespace
305 class ServiceWorkerBrowserTest : public ContentBrowserTest {
306 protected:
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
322 // a worker).
323 NavigateToURLBlockUntilNavigationsComplete(
324 shell(),
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));
332 wrapper_ = NULL;
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());
346 private:
347 scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
350 class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
351 public EmbeddedWorkerInstance::Listener {
352 public:
353 using self = EmbeddedWorkerBrowserTest;
355 EmbeddedWorkerBrowserTest()
356 : last_worker_status_(EmbeddedWorkerInstance::STOPPED) {}
357 ~EmbeddedWorkerBrowserTest() override {}
359 void TearDownOnIOThread() override {
360 if (worker_) {
361 worker_->RemoveListener(this);
362 if (worker_->status() == EmbeddedWorkerInstance::STARTING ||
363 worker_->status() == EmbeddedWorkerInstance::RUNNING) {
364 worker_->Stop();
366 worker_.reset();
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);
392 worker_->Start(
393 service_worker_version_id,
394 pattern,
395 script_url,
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())
405 done_closure_.Run();
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())
419 done_closure_.Run();
422 protected:
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,
437 int line_number,
438 int column_number,
439 const GURL& source_url) override {}
440 void OnReportConsoleMessage(int source_identifier,
441 int message_level,
442 const base::string16& message,
443 int line_number,
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 {
456 public:
457 void OnReportConsoleMessage(int source_identifier,
458 int message_level,
459 const base::string16& message,
460 int line_number,
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_);
465 quit_.Reset();
469 void WaitForConsoleMessages(size_t expected_message_count) {
470 if (messages_.size() >= expected_message_count)
471 return;
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_; }
484 private:
485 std::vector<base::string16> messages_;
486 size_t expected_message_count_;
487 base::Closure quit_;
490 class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
491 public:
492 using self = ServiceWorkerVersionBrowserTest;
494 ~ServiceWorkerVersionBrowserTest() override {}
496 void TearDownOnIOThread() override {
497 registration_ = NULL;
498 version_ = NULL;
501 void InstallTestHelper(const std::string& worker_url,
502 ServiceWorkerStatusCode expected_status) {
503 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
504 worker_url));
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(),
512 &status));
513 install_run_loop.Run();
514 ASSERT_EQ(expected_status, status);
516 // Stop the worker.
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(),
522 &status));
523 stop_run_loop.Run();
524 ASSERT_EQ(SERVICE_WORKER_OK, status);
527 void ActivateTestHelper(
528 const std::string& worker_url,
529 ServiceWorkerStatusCode expected_status) {
530 RunOnIOThread(
531 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
532 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
533 base::RunLoop run_loop;
534 BrowserThread::PostTask(
535 BrowserThread::IO,
536 FROM_HERE,
537 base::Bind(
538 &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status));
539 run_loop.Run();
540 ASSERT_EQ(expected_status, status);
543 base::string16 RunSyncTestWithConsoleOutput(
544 const std::string& worker_url,
545 ServiceWorkerStatusCode expected_status) {
546 RunOnIOThread(
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));
557 sync_run_loop.Run();
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,
585 FROM_HERE,
586 base::Bind(&self::FetchOnIOThread,
587 this,
588 fetch_run_loop.QuitClosure(),
589 &prepare_result,
590 &fetch_result));
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) {
603 RunOnIOThread(
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(
612 pattern,
613 wrapper()->context()->storage()->NewRegistrationId(),
614 wrapper()->context()->AsWeakPtr());
615 version_ = new ServiceWorkerVersion(
616 registration_.get(),
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(),
639 NULL));
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(),
666 &status));
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(),
678 &status));
679 stop_run_loop.Run();
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,
696 this, status));
699 void FindRegistrationForId(int64 id,
700 const GURL& origin,
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));
709 run_loop.Run();
710 ASSERT_EQ(expected_status, status);
713 void FindRegistrationForIdOnIOThread(const base::Closure& done,
714 ServiceWorkerStatusCode* result,
715 int64 id,
716 const GURL& origin) {
717 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
718 wrapper()->context()->storage()->FindRegistrationForId(
719 id, origin,
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,
751 int64 version_id) {
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"),
775 "GET",
776 ServiceWorkerHeaderMap(),
777 Referrer(),
778 false);
779 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
780 version_->DispatchFetchEvent(
781 request,
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));
802 protected:
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));
823 stop_run_loop.Run();
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"));
832 // Start a worker.
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(),
838 &status));
839 start_run_loop.Run();
840 ASSERT_EQ(SERVICE_WORKER_OK, status);
842 // Stop the worker.
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(),
848 &status));
849 stop_run_loop.Run();
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;
869 records.push_back(
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
881 // the stored one.
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;
908 records.push_back(
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(),
917 SERVICE_WORKER_OK);
919 // Start the broken worker. We'll fail to read from disk and the worker should
920 // be doomed.
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
926 // the stored one.
927 RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread, this,
928 registration_->id()));
929 FindRegistrationForId(registration_->id(),
930 registration_->pattern().GetOrigin(),
931 SERVICE_WORKER_OK);
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",
941 SERVICE_WORKER_OK);
944 // Check that ServiceWorker script requests set a "Service-Worker: script"
945 // header.
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 {
996 public:
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; }
1004 private:
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"));
1045 // Start a worker.
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);
1084 std::string body;
1085 RunOnIOThread(
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,
1134 FROM_HERE,
1135 base::Bind(&self::SyncEventOnIOThread,
1136 this,
1137 sync_run_loop.QuitClosure(),
1138 &status));
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
1182 #else
1183 #define MAYBE_SyncEventWaitUntil_Rejected SyncEventWaitUntil_Rejected
1184 #endif
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());
1202 observer->Init();
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)));
1207 observer->Wait();
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());
1219 shell()->Close();
1221 base::RunLoop run_loop;
1222 public_context()->UnregisterServiceWorker(
1223 embedded_test_server()->GetURL(kPageUrl),
1224 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1225 run_loop.Run();
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());
1241 observer->Init();
1242 public_context()->RegisterServiceWorker(
1243 https_server.GetURL(kPageUrl),
1244 https_server.GetURL(kWorkerUrl),
1245 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
1246 observer->Wait();
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);
1257 shell()->Close();
1259 base::RunLoop run_loop;
1260 public_context()->UnregisterServiceWorker(
1261 https_server.GetURL(kPageUrl),
1262 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1263 run_loop.Run();
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());
1272 observer->Init();
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)));
1277 observer->Wait();
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);
1288 shell()->Close();
1290 base::RunLoop run_loop;
1291 public_context()->UnregisterServiceWorker(
1292 embedded_test_server()->GetURL(kPageUrl),
1293 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1294 run_loop.Run();
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"));
1305 RunOnIOThread(
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;
1319 RunOnIOThread(
1320 base::Bind(&CountScriptResources,
1321 base::Unretained(wrapper()),
1322 embedded_test_server()->GetURL(kScopeUrl),
1323 &num_resources));
1324 EXPECT_EQ(kExpectedNumResources, num_resources);
1327 class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
1328 public:
1329 using self = ServiceWorkerBlackBoxBrowserTest;
1331 void FindRegistrationOnIO(const GURL& document_url,
1332 ServiceWorkerStatusCode* status,
1333 const base::Closure& continuation) {
1334 wrapper()->FindRegistrationForDocument(
1335 document_url,
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);
1348 continuation.Run();
1352 static int CountRenderProcessHosts() {
1353 int result = 0;
1354 for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
1355 !iter.IsAtEnd();
1356 iter.Advance()) {
1357 result++;
1359 return result;
1362 // Flaky timeouts on CrOS: http://crbug.com/387045
1363 #if defined(OS_CHROMEOS)
1364 #define MAYBE_Registration DISABLED_Registration
1365 #else
1366 #define MAYBE_Registration Registration
1367 #endif
1368 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
1369 // Close the only window to be sure we're not re-using its RenderProcessHost.
1370 shell()->Close();
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()));
1382 run_loop.Run();
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()));
1392 run_loop.Run();
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()));
1403 run_loop.Run();
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()));
1415 run_loop.Run();
1418 // The registration algo might not be far enough along to have
1419 // stored the registration data, so it may not be findable
1420 // at this point.
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()));
1428 run_loop.Run();
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;
1437 RunOnIOThread(
1438 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
1439 this,
1440 embedded_test_server()->GetURL("/service_worker/empty.html"),
1441 &status));
1442 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
1446 #if defined(ANDROID)
1447 #define MAYBE_CrossSiteTransfer DISABLED_CrossSiteTransfer
1448 #else
1449 #define MAYBE_CrossSiteTransfer CrossSiteTransfer
1450 #endif
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 {
1481 public:
1482 using self = ServiceWorkerVersionBrowserV8CacheTest;
1483 ~ServiceWorkerVersionBrowserV8CacheTest() override {
1484 if (version_)
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);
1496 protected:
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();
1513 // Start a worker.
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);
1528 // Stop the worker.
1529 StopWorker(SERVICE_WORKER_OK);
1530 // Restart the worker.
1531 StartWorker(SERVICE_WORKER_OK);
1532 // Stop the worker.
1533 StopWorker(SERVICE_WORKER_OK);
1536 } // namespace content