Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_browsertest.cc
blobb841b1862894514f24527879abbcf2164e7fba98
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 class WorkerActivatedObserver
175 : public ServiceWorkerContextObserver,
176 public base::RefCountedThreadSafe<WorkerActivatedObserver> {
177 public:
178 explicit WorkerActivatedObserver(ServiceWorkerContextWrapper* context)
179 : context_(context) {}
180 void Init() {
181 RunOnIOThread(base::Bind(&WorkerActivatedObserver::InitOnIOThread, this));
183 // ServiceWorkerContextObserver overrides.
184 void OnVersionStateChanged(int64 version_id,
185 ServiceWorkerVersion::Status) override {
186 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
187 const ServiceWorkerVersion* version = context_->GetLiveVersion(version_id);
188 if (version->status() == ServiceWorkerVersion::ACTIVATED) {
189 context_->RemoveObserver(this);
190 BrowserThread::PostTask(BrowserThread::UI,
191 FROM_HERE,
192 base::Bind(&WorkerActivatedObserver::Quit, this));
195 void Wait() { run_loop_.Run(); }
197 private:
198 friend class base::RefCountedThreadSafe<WorkerActivatedObserver>;
199 ~WorkerActivatedObserver() override {}
200 void InitOnIOThread() { context_->AddObserver(this); }
201 void Quit() { run_loop_.Quit(); }
203 base::RunLoop run_loop_;
204 ServiceWorkerContextWrapper* context_;
205 DISALLOW_COPY_AND_ASSIGN(WorkerActivatedObserver);
208 scoped_ptr<net::test_server::HttpResponse> VerifyServiceWorkerHeaderInRequest(
209 const net::test_server::HttpRequest& request) {
210 EXPECT_EQ(request.relative_url, "/service_worker/generated_sw.js");
211 std::map<std::string, std::string>::const_iterator it =
212 request.headers.find("Service-Worker");
213 EXPECT_TRUE(it != request.headers.end());
214 EXPECT_EQ("script", it->second);
216 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
217 new net::test_server::BasicHttpResponse());
218 http_response->set_content_type("text/javascript");
219 return http_response.Pass();
222 // The ImportsBustMemcache test requires that the imported script
223 // would naturally be cached in blink's memcache, but the embedded
224 // test server doesn't produce headers that allow the blink's memcache
225 // to do that. This interceptor injects headers that give the import
226 // an experiration far in the future.
227 class LongLivedResourceInterceptor : public net::URLRequestInterceptor {
228 public:
229 LongLivedResourceInterceptor(const std::string& body)
230 : body_(body) {}
231 ~LongLivedResourceInterceptor() override {}
233 // net::URLRequestInterceptor implementation
234 net::URLRequestJob* MaybeInterceptRequest(
235 net::URLRequest* request,
236 net::NetworkDelegate* network_delegate) const override {
237 const char kHeaders[] =
238 "HTTP/1.1 200 OK\0"
239 "Content-Type: text/javascript\0"
240 "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
241 "\0";
242 std::string headers(kHeaders, arraysize(kHeaders));
243 return new net::URLRequestTestJob(
244 request, network_delegate, headers, body_, true);
247 private:
248 std::string body_;
249 DISALLOW_COPY_AND_ASSIGN(LongLivedResourceInterceptor);
252 void CreateLongLivedResourceInterceptors(
253 const GURL& worker_url, const GURL& import_url) {
254 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
255 scoped_ptr<net::URLRequestInterceptor> interceptor;
257 interceptor.reset(new LongLivedResourceInterceptor(
258 "importScripts('long_lived_import.js');"));
259 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
260 worker_url, interceptor.Pass());
262 interceptor.reset(new LongLivedResourceInterceptor(
263 "// the imported script does nothing"));
264 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
265 import_url, interceptor.Pass());
268 void CountScriptResources(
269 ServiceWorkerContextWrapper* wrapper,
270 const GURL& scope,
271 int* num_resources) {
272 *num_resources = -1;
274 std::vector<ServiceWorkerRegistrationInfo> infos =
275 wrapper->GetAllLiveRegistrationInfo();
276 if (infos.empty())
277 return;
279 int version_id;
280 size_t index = infos.size() - 1;
281 if (infos[index].installing_version.version_id !=
282 kInvalidServiceWorkerVersionId)
283 version_id = infos[index].installing_version.version_id;
284 else if (infos[index].waiting_version.version_id !=
285 kInvalidServiceWorkerVersionId)
286 version_id = infos[1].waiting_version.version_id;
287 else if (infos[index].active_version.version_id !=
288 kInvalidServiceWorkerVersionId)
289 version_id = infos[index].active_version.version_id;
290 else
291 return;
293 ServiceWorkerVersion* version = wrapper->GetLiveVersion(version_id);
294 *num_resources = static_cast<int>(version->script_cache_map()->size());
297 } // namespace
299 class ServiceWorkerBrowserTest : public ContentBrowserTest {
300 protected:
301 using self = ServiceWorkerBrowserTest;
303 void SetUpCommandLine(base::CommandLine* command_line) override {
304 command_line->AppendSwitch(
305 switches::kEnableExperimentalWebPlatformFeatures);
308 void SetUpOnMainThread() override {
309 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
310 StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
311 shell()->web_contents()->GetBrowserContext());
312 wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
313 partition->GetServiceWorkerContext());
315 // Navigate to the page to set up a renderer page (where we can embed
316 // a worker).
317 NavigateToURLBlockUntilNavigationsComplete(
318 shell(),
319 embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
321 RunOnIOThread(base::Bind(&self::SetUpOnIOThread, this));
324 void TearDownOnMainThread() override {
325 RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this));
326 wrapper_ = NULL;
329 virtual void SetUpOnIOThread() {}
330 virtual void TearDownOnIOThread() {}
332 ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
333 ServiceWorkerContext* public_context() { return wrapper(); }
335 void AssociateRendererProcessToPattern(const GURL& pattern) {
336 wrapper_->process_manager()->AddProcessReferenceToPattern(
337 pattern, shell()->web_contents()->GetRenderProcessHost()->GetID());
340 private:
341 scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
344 class ConsoleListener : public EmbeddedWorkerInstance::Listener {
345 public:
346 void OnReportConsoleMessage(int source_identifier,
347 int message_level,
348 const base::string16& message,
349 int line_number,
350 const GURL& source_url) override {
351 messages_.push_back(message);
352 if (!quit_.is_null() && messages_.size() == expected_message_count_) {
353 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_);
354 quit_.Reset();
358 void WaitForConsoleMessages(size_t expected_message_count) {
359 if (messages_.size() >= expected_message_count)
360 return;
362 expected_message_count_ = expected_message_count;
363 base::RunLoop console_run_loop;
364 quit_ = console_run_loop.QuitClosure();
365 console_run_loop.Run();
367 ASSERT_EQ(messages_.size(), expected_message_count);
370 bool OnMessageReceived(const IPC::Message& message) override { return false; }
371 const std::vector<base::string16>& messages() const { return messages_; }
373 private:
374 std::vector<base::string16> messages_;
375 size_t expected_message_count_;
376 base::Closure quit_;
379 class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
380 public:
381 using self = ServiceWorkerVersionBrowserTest;
383 ~ServiceWorkerVersionBrowserTest() override {}
385 void TearDownOnIOThread() override {
386 registration_ = NULL;
387 version_ = NULL;
390 void InstallTestHelper(const std::string& worker_url,
391 ServiceWorkerStatusCode expected_status) {
392 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
393 worker_url));
395 // Dispatch install on a worker.
396 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
397 base::RunLoop install_run_loop;
398 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
399 base::Bind(&self::InstallOnIOThread, this,
400 install_run_loop.QuitClosure(),
401 &status));
402 install_run_loop.Run();
403 ASSERT_EQ(expected_status, status);
405 // Stop the worker.
406 status = SERVICE_WORKER_ERROR_FAILED;
407 base::RunLoop stop_run_loop;
408 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
409 base::Bind(&self::StopOnIOThread, this,
410 stop_run_loop.QuitClosure(),
411 &status));
412 stop_run_loop.Run();
413 ASSERT_EQ(SERVICE_WORKER_OK, status);
416 void ActivateTestHelper(
417 const std::string& worker_url,
418 ServiceWorkerStatusCode expected_status) {
419 RunOnIOThread(
420 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
421 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
422 base::RunLoop run_loop;
423 BrowserThread::PostTask(
424 BrowserThread::IO,
425 FROM_HERE,
426 base::Bind(
427 &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status));
428 run_loop.Run();
429 ASSERT_EQ(expected_status, status);
432 void FetchOnRegisteredWorker(
433 ServiceWorkerFetchEventResult* result,
434 ServiceWorkerResponse* response,
435 scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
436 blob_context_ = ChromeBlobStorageContext::GetFor(
437 shell()->web_contents()->GetBrowserContext());
438 bool prepare_result = false;
439 FetchResult fetch_result;
440 fetch_result.status = SERVICE_WORKER_ERROR_FAILED;
441 base::RunLoop fetch_run_loop;
442 BrowserThread::PostTask(BrowserThread::IO,
443 FROM_HERE,
444 base::Bind(&self::FetchOnIOThread,
445 this,
446 fetch_run_loop.QuitClosure(),
447 &prepare_result,
448 &fetch_result));
449 fetch_run_loop.Run();
450 ASSERT_TRUE(prepare_result);
451 *result = fetch_result.result;
452 *response = fetch_result.response;
453 *blob_data_handle = fetch_result.blob_data_handle.Pass();
454 ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status);
457 void FetchTestHelper(const std::string& worker_url,
458 ServiceWorkerFetchEventResult* result,
459 ServiceWorkerResponse* response,
460 scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
461 RunOnIOThread(
462 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
463 FetchOnRegisteredWorker(result, response, blob_data_handle);
466 void SetUpRegistrationOnIOThread(const std::string& worker_url) {
467 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
468 const GURL pattern = embedded_test_server()->GetURL("/service_worker/");
469 registration_ = new ServiceWorkerRegistration(
470 pattern,
471 wrapper()->context()->storage()->NewRegistrationId(),
472 wrapper()->context()->AsWeakPtr());
473 version_ = new ServiceWorkerVersion(
474 registration_.get(),
475 embedded_test_server()->GetURL(worker_url),
476 wrapper()->context()->storage()->NewVersionId(),
477 wrapper()->context()->AsWeakPtr());
479 // Make the registration findable via storage functions.
480 wrapper()->context()->storage()->NotifyInstallingRegistration(
481 registration_.get());
483 AssociateRendererProcessToPattern(pattern);
486 void TimeoutWorkerOnIOThread() {
487 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
488 version_->SimulatePingTimeoutForTesting();
491 void AddControlleeOnIOThread() {
492 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
493 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
494 33 /* dummy render process id */,
495 MSG_ROUTING_NONE /* render_frame_id */, 1 /* dummy provider_id */,
496 SERVICE_WORKER_PROVIDER_FOR_WINDOW, wrapper()->context()->AsWeakPtr(),
497 NULL));
498 host->SetDocumentUrl(
499 embedded_test_server()->GetURL("/service_worker/host"));
500 host->AssociateRegistration(registration_.get(),
501 false /* notify_controllerchange */);
502 wrapper()->context()->AddProviderHost(host.Pass());
505 void AddWaitingWorkerOnIOThread(const std::string& worker_url) {
506 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
507 scoped_refptr<ServiceWorkerVersion> waiting_version(
508 new ServiceWorkerVersion(
509 registration_.get(), embedded_test_server()->GetURL(worker_url),
510 wrapper()->context()->storage()->NewVersionId(),
511 wrapper()->context()->AsWeakPtr()));
512 waiting_version->SetStatus(ServiceWorkerVersion::INSTALLED);
513 registration_->SetWaitingVersion(waiting_version.get());
514 registration_->ActivateWaitingVersionWhenReady();
517 void StartWorker(ServiceWorkerStatusCode expected_status) {
518 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
519 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
520 base::RunLoop start_run_loop;
521 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
522 base::Bind(&self::StartOnIOThread, this,
523 start_run_loop.QuitClosure(),
524 &status));
525 start_run_loop.Run();
526 ASSERT_EQ(expected_status, status);
529 void StopWorker(ServiceWorkerStatusCode expected_status) {
530 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
531 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
532 base::RunLoop stop_run_loop;
533 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
534 base::Bind(&self::StopOnIOThread, this,
535 stop_run_loop.QuitClosure(),
536 &status));
537 stop_run_loop.Run();
538 ASSERT_EQ(expected_status, status);
541 void StoreRegistration(int64 version_id,
542 ServiceWorkerStatusCode expected_status) {
543 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
544 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
545 base::RunLoop store_run_loop;
546 BrowserThread::PostTask(
547 BrowserThread::IO, FROM_HERE,
548 base::Bind(&self::StoreOnIOThread, this, store_run_loop.QuitClosure(),
549 &status, version_id));
550 store_run_loop.Run();
551 ASSERT_EQ(expected_status, status);
553 RunOnIOThread(base::Bind(&self::NotifyDoneInstallingRegistrationOnIOThread,
554 this, status));
557 void FindRegistrationForId(int64 id,
558 const GURL& origin,
559 ServiceWorkerStatusCode expected_status) {
560 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
561 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
562 base::RunLoop run_loop;
563 BrowserThread::PostTask(
564 BrowserThread::IO, FROM_HERE,
565 base::Bind(&self::FindRegistrationForIdOnIOThread, this,
566 run_loop.QuitClosure(), &status, id, origin));
567 run_loop.Run();
568 ASSERT_EQ(expected_status, status);
571 void FindRegistrationForIdOnIOThread(const base::Closure& done,
572 ServiceWorkerStatusCode* result,
573 int64 id,
574 const GURL& origin) {
575 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
576 wrapper()->context()->storage()->FindRegistrationForId(
577 id, origin,
578 CreateFindRegistrationReceiver(BrowserThread::UI, done, result));
581 void NotifyDoneInstallingRegistrationOnIOThread(
582 ServiceWorkerStatusCode status) {
583 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
584 wrapper()->context()->storage()->NotifyDoneInstallingRegistration(
585 registration_.get(), version_.get(), status);
588 void RemoveLiveRegistrationOnIOThread(int64 id) {
589 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
590 wrapper()->context()->RemoveLiveRegistration(id);
593 void StartOnIOThread(const base::Closure& done,
594 ServiceWorkerStatusCode* result) {
595 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
596 version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result));
599 void InstallOnIOThread(const base::Closure& done,
600 ServiceWorkerStatusCode* result) {
601 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
602 version_->SetStatus(ServiceWorkerVersion::INSTALLING);
603 version_->DispatchInstallEvent(
604 CreateReceiver(BrowserThread::UI, done, result));
607 void StoreOnIOThread(const base::Closure& done,
608 ServiceWorkerStatusCode* result,
609 int64 version_id) {
610 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
611 ServiceWorkerVersion* version =
612 wrapper()->context()->GetLiveVersion(version_id);
613 wrapper()->context()->storage()->StoreRegistration(
614 registration_.get(), version,
615 CreateReceiver(BrowserThread::UI, done, result));
618 void ActivateOnIOThread(const base::Closure& done,
619 ServiceWorkerStatusCode* result) {
620 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
621 version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
622 registration_->SetActiveVersion(version_.get());
623 version_->DispatchActivateEvent(
624 CreateReceiver(BrowserThread::UI, done, result));
627 void FetchOnIOThread(const base::Closure& done,
628 bool* prepare_result,
629 FetchResult* result) {
630 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
631 ServiceWorkerFetchRequest request(
632 embedded_test_server()->GetURL("/service_worker/empty.html"),
633 "GET",
634 ServiceWorkerHeaderMap(),
635 Referrer(),
636 false);
637 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
638 version_->DispatchFetchEvent(
639 request,
640 CreatePrepareReceiver(prepare_result),
641 CreateResponseReceiver(
642 BrowserThread::UI, done, blob_context_.get(), result));
645 void StopOnIOThread(const base::Closure& done,
646 ServiceWorkerStatusCode* result) {
647 ASSERT_TRUE(version_.get());
648 version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
651 protected:
652 scoped_refptr<ServiceWorkerRegistration> registration_;
653 scoped_refptr<ServiceWorkerVersion> version_;
654 scoped_refptr<ChromeBlobStorageContext> blob_context_;
657 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
658 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
659 "/service_worker/worker.js"));
661 // Start a worker.
662 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
663 base::RunLoop start_run_loop;
664 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
665 base::Bind(&self::StartOnIOThread, this,
666 start_run_loop.QuitClosure(),
667 &status));
668 start_run_loop.Run();
669 ASSERT_EQ(SERVICE_WORKER_OK, status);
671 // Stop the worker.
672 status = SERVICE_WORKER_ERROR_FAILED;
673 base::RunLoop stop_run_loop;
674 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
675 base::Bind(&self::StopOnIOThread, this,
676 stop_run_loop.QuitClosure(),
677 &status));
678 stop_run_loop.Run();
679 ASSERT_EQ(SERVICE_WORKER_OK, status);
682 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
683 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
684 "/service_worker/nonexistent.js"));
686 // Start a worker for nonexistent URL.
687 StartWorker(SERVICE_WORKER_ERROR_NETWORK);
690 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, ReadResourceFailure) {
691 // Create a registration.
692 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
693 "/service_worker/worker.js"));
694 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
696 // Add a non-existent resource to the version.
697 std::vector<ServiceWorkerDatabase::ResourceRecord> records;
698 records.push_back(
699 ServiceWorkerDatabase::ResourceRecord(30, version_->script_url(), 100));
700 version_->script_cache_map()->SetResources(records);
702 // Store the registration.
703 StoreRegistration(version_->version_id(), SERVICE_WORKER_OK);
705 // Start the worker. We'll fail to read the resource.
706 StartWorker(SERVICE_WORKER_ERROR_DISK_CACHE);
707 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version_->status());
709 // The registration should be deleted from storage since the broken worker was
710 // the stored one.
711 RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread, this,
712 registration_->id()));
713 FindRegistrationForId(registration_->id(),
714 registration_->pattern().GetOrigin(),
715 SERVICE_WORKER_ERROR_NOT_FOUND);
718 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
719 ReadResourceFailure_WaitingWorker) {
720 // Create a registration and active version.
721 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
722 "/service_worker/worker.js"));
723 base::RunLoop activate_run_loop;
724 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
725 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
726 base::Bind(&self::ActivateOnIOThread, this,
727 activate_run_loop.QuitClosure(), &status));
728 activate_run_loop.Run();
729 EXPECT_EQ(SERVICE_WORKER_OK, status);
730 ASSERT_TRUE(registration_->active_version());
732 // Give the version a controllee.
733 RunOnIOThread(base::Bind(&self::AddControlleeOnIOThread, this));
735 // Add a non-existent resource to the version.
736 std::vector<ServiceWorkerDatabase::ResourceRecord> records;
737 records.push_back(
738 ServiceWorkerDatabase::ResourceRecord(30, version_->script_url(), 100));
739 version_->script_cache_map()->SetResources(records);
741 // Make a waiting version and store it.
742 RunOnIOThread(base::Bind(&self::AddWaitingWorkerOnIOThread, this,
743 "/service_worker/worker.js"));
744 registration_->waiting_version()->script_cache_map()->SetResources(records);
745 StoreRegistration(registration_->waiting_version()->version_id(),
746 SERVICE_WORKER_OK);
748 // Start the broken worker. We'll fail to read from disk and the worker should
749 // be doomed.
750 StopWorker(SERVICE_WORKER_OK); // in case it's already running
751 StartWorker(SERVICE_WORKER_ERROR_DISK_CACHE);
752 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version_->status());
754 // The registration should still be in storage since the waiting worker was
755 // the stored one.
756 RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread, this,
757 registration_->id()));
758 FindRegistrationForId(registration_->id(),
759 registration_->pattern().GetOrigin(),
760 SERVICE_WORKER_OK);
763 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
764 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
767 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
768 InstallWithWaitUntil_Fulfilled) {
769 InstallTestHelper("/service_worker/worker_install_fulfilled.js",
770 SERVICE_WORKER_OK);
773 // Check that ServiceWorker script requests set a "Service-Worker: script"
774 // header.
775 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
776 ServiceWorkerScriptHeader) {
777 embedded_test_server()->RegisterRequestHandler(
778 base::Bind(&VerifyServiceWorkerHeaderInRequest));
779 InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
782 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
783 Activate_NoEventListener) {
784 ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
785 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
788 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
789 ActivateTestHelper("/service_worker/worker_activate_rejected.js",
790 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
793 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
794 InstallWithWaitUntil_Rejected) {
795 InstallTestHelper("/service_worker/worker_install_rejected.js",
796 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
799 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
800 InstallWithWaitUntil_RejectConsoleMessage) {
801 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
802 "/service_worker/worker_install_rejected.js"));
804 ConsoleListener console_listener;
805 version_->embedded_worker()->AddListener(&console_listener);
807 // Dispatch install on a worker.
808 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
809 base::RunLoop install_run_loop;
810 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
811 base::Bind(&self::InstallOnIOThread, this,
812 install_run_loop.QuitClosure(), &status));
813 install_run_loop.Run();
814 ASSERT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, status);
816 const base::string16 expected =
817 base::ASCIIToUTF16("Rejecting oninstall event");
818 console_listener.WaitForConsoleMessages(1);
819 ASSERT_NE(base::string16::npos,
820 console_listener.messages()[0].find(expected));
821 version_->embedded_worker()->RemoveListener(&console_listener);
824 class WaitForLoaded : public EmbeddedWorkerInstance::Listener {
825 public:
826 WaitForLoaded(const base::Closure& quit) : quit_(quit) {}
828 void OnThreadStarted() override {
829 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_);
831 bool OnMessageReceived(const IPC::Message& message) override { return false; }
833 private:
834 base::Closure quit_;
837 // This test has started flaking somewhat consistently on Win, Mac and Linux.
838 // Disabling for now, see http://crbug.com/496065.
839 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
840 DISABLED_TimeoutStartingWorker) {
841 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
842 "/service_worker/while_true_worker.js"));
844 // Start a worker, waiting until the script is loaded.
845 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
846 base::RunLoop start_run_loop;
847 base::RunLoop load_run_loop;
848 WaitForLoaded wait_for_load(load_run_loop.QuitClosure());
849 version_->embedded_worker()->AddListener(&wait_for_load);
850 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
851 base::Bind(&self::StartOnIOThread, this,
852 start_run_loop.QuitClosure(), &status));
853 load_run_loop.Run();
854 version_->embedded_worker()->RemoveListener(&wait_for_load);
856 // The script has loaded but start has not completed yet.
857 ASSERT_EQ(SERVICE_WORKER_ERROR_FAILED, status);
858 EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
860 // Simulate execution timeout. Use a delay to prevent killing the worker
861 // before it's started execution.
862 EXPECT_TRUE(version_->timeout_timer_.IsRunning());
863 RunOnIOThreadWithDelay(base::Bind(&self::TimeoutWorkerOnIOThread, this),
864 base::TimeDelta::FromMilliseconds(100));
865 start_run_loop.Run();
867 EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
870 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, TimeoutWorkerInEvent) {
871 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
872 "/service_worker/while_true_in_install_worker.js"));
874 // Start a worker.
875 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
876 base::RunLoop start_run_loop;
877 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
878 base::Bind(&self::StartOnIOThread, this,
879 start_run_loop.QuitClosure(), &status));
880 start_run_loop.Run();
881 ASSERT_EQ(SERVICE_WORKER_OK, status);
883 // Dispatch an event.
884 base::RunLoop install_run_loop;
885 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
886 base::Bind(&self::InstallOnIOThread, this,
887 install_run_loop.QuitClosure(), &status));
889 // Simulate execution timeout. Use a delay to prevent killing the worker
890 // before it's started execution.
891 EXPECT_TRUE(version_->timeout_timer_.IsRunning());
892 RunOnIOThreadWithDelay(base::Bind(&self::TimeoutWorkerOnIOThread, this),
893 base::TimeDelta::FromMilliseconds(100));
894 install_run_loop.Run();
896 EXPECT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, status);
899 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
900 ServiceWorkerFetchEventResult result;
901 ServiceWorkerResponse response;
902 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
903 FetchTestHelper("/service_worker/fetch_event.js",
904 &result, &response, &blob_data_handle);
905 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
906 EXPECT_EQ(301, response.status_code);
907 EXPECT_EQ("Moved Permanently", response.status_text);
908 ServiceWorkerHeaderMap expected_headers;
909 expected_headers["content-language"] = "fi";
910 expected_headers["content-type"] = "text/html; charset=UTF-8";
911 EXPECT_EQ(expected_headers, response.headers);
913 std::string body;
914 RunOnIOThread(
915 base::Bind(&ReadResponseBody,
916 &body, base::Owned(blob_data_handle.release())));
917 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body);
920 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
921 FetchEvent_respondWithRejection) {
922 ServiceWorkerFetchEventResult result;
923 ServiceWorkerResponse response;
924 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
926 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
927 "/service_worker/fetch_event_rejected.js"));
929 ConsoleListener console_listener;
930 version_->embedded_worker()->AddListener(&console_listener);
932 FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
933 const base::string16 expected1 = base::ASCIIToUTF16(
934 "resulted in a network error response: the promise was rejected.");
935 const base::string16 expected2 =
936 base::ASCIIToUTF16("Uncaught (in promise) Rejecting respondWith promise");
937 console_listener.WaitForConsoleMessages(2);
938 ASSERT_NE(base::string16::npos,
939 console_listener.messages()[0].find(expected1));
940 ASSERT_EQ(0u, console_listener.messages()[1].find(expected2));
941 version_->embedded_worker()->RemoveListener(&console_listener);
943 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
944 EXPECT_EQ(0, response.status_code);
946 ASSERT_FALSE(blob_data_handle);
949 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, Reload) {
950 const char kPageUrl[] = "/service_worker/reload.html";
951 const char kWorkerUrl[] = "/service_worker/fetch_event_reload.js";
952 scoped_refptr<WorkerActivatedObserver> observer =
953 new WorkerActivatedObserver(wrapper());
954 observer->Init();
955 public_context()->RegisterServiceWorker(
956 embedded_test_server()->GetURL(kPageUrl),
957 embedded_test_server()->GetURL(kWorkerUrl),
958 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
959 observer->Wait();
961 const base::string16 title1 = base::ASCIIToUTF16("reload=false");
962 TitleWatcher title_watcher1(shell()->web_contents(), title1);
963 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
964 EXPECT_EQ(title1, title_watcher1.WaitAndGetTitle());
966 const base::string16 title2 = base::ASCIIToUTF16("reload=true");
967 TitleWatcher title_watcher2(shell()->web_contents(), title2);
968 ReloadBlockUntilNavigationsComplete(shell(), 1);
969 EXPECT_EQ(title2, title_watcher2.WaitAndGetTitle());
971 shell()->Close();
973 base::RunLoop run_loop;
974 public_context()->UnregisterServiceWorker(
975 embedded_test_server()->GetURL(kPageUrl),
976 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
977 run_loop.Run();
980 // Flaky on Win/Mac: http://crbug.com/533631
981 #if defined(OS_WIN) || defined(OS_MACOSX)
982 #define MAYBE_ResponseFromHTTPSServiceWorkerIsMarkedAsSecure DISABLED_ResponseFromHTTPSServiceWorkerIsMarkedAsSecure
983 #else
984 #define MAYBE_ResponseFromHTTPSServiceWorkerIsMarkedAsSecure ResponseFromHTTPSServiceWorkerIsMarkedAsSecure
985 #endif
986 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
987 MAYBE_ResponseFromHTTPSServiceWorkerIsMarkedAsSecure) {
988 const char kPageUrl[] = "files/service_worker/fetch_event_blob.html";
989 const char kWorkerUrl[] = "files/service_worker/fetch_event_blob.js";
990 net::SpawnedTestServer https_server(
991 net::SpawnedTestServer::TYPE_HTTPS,
992 net::BaseTestServer::SSLOptions(
993 net::BaseTestServer::SSLOptions::CERT_OK),
994 base::FilePath(FILE_PATH_LITERAL("content/test/data/")));
995 ASSERT_TRUE(https_server.Start());
997 scoped_refptr<WorkerActivatedObserver> observer =
998 new WorkerActivatedObserver(wrapper());
999 observer->Init();
1000 public_context()->RegisterServiceWorker(
1001 https_server.GetURL(kPageUrl),
1002 https_server.GetURL(kWorkerUrl),
1003 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
1004 observer->Wait();
1006 const base::string16 title = base::ASCIIToUTF16("Title");
1007 TitleWatcher title_watcher(shell()->web_contents(), title);
1008 NavigateToURL(shell(), https_server.GetURL(kPageUrl));
1009 EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
1010 EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
1011 NavigationEntry* entry =
1012 shell()->web_contents()->GetController().GetVisibleEntry();
1013 EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, entry->GetSSL().security_style);
1015 shell()->Close();
1017 base::RunLoop run_loop;
1018 public_context()->UnregisterServiceWorker(
1019 https_server.GetURL(kPageUrl),
1020 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1021 run_loop.Run();
1024 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
1025 ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure) {
1026 const char kPageUrl[] = "/service_worker/fetch_event_blob.html";
1027 const char kWorkerUrl[] = "/service_worker/fetch_event_blob.js";
1028 scoped_refptr<WorkerActivatedObserver> observer =
1029 new WorkerActivatedObserver(wrapper());
1030 observer->Init();
1031 public_context()->RegisterServiceWorker(
1032 embedded_test_server()->GetURL(kPageUrl),
1033 embedded_test_server()->GetURL(kWorkerUrl),
1034 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
1035 observer->Wait();
1037 const base::string16 title = base::ASCIIToUTF16("Title");
1038 TitleWatcher title_watcher(shell()->web_contents(), title);
1039 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
1040 EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
1041 EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
1042 NavigationEntry* entry =
1043 shell()->web_contents()->GetController().GetVisibleEntry();
1044 EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, entry->GetSSL().security_style);
1046 shell()->Close();
1048 base::RunLoop run_loop;
1049 public_context()->UnregisterServiceWorker(
1050 embedded_test_server()->GetURL(kPageUrl),
1051 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1052 run_loop.Run();
1055 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
1056 const char kScopeUrl[] = "/service_worker/imports_bust_memcache_scope/";
1057 const char kPageUrl[] = "/service_worker/imports_bust_memcache.html";
1058 const char kScriptUrl[] = "/service_worker/worker_with_one_import.js";
1059 const char kImportUrl[] = "/service_worker/long_lived_import.js";
1060 const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
1061 const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
1063 RunOnIOThread(
1064 base::Bind(&CreateLongLivedResourceInterceptors,
1065 embedded_test_server()->GetURL(kScriptUrl),
1066 embedded_test_server()->GetURL(kImportUrl)));
1068 TitleWatcher title_watcher(shell()->web_contents(), kOKTitle);
1069 title_watcher.AlsoWaitForTitle(kFailTitle);
1070 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
1071 base::string16 title = title_watcher.WaitAndGetTitle();
1072 EXPECT_EQ(kOKTitle, title);
1074 // Verify the number of resources in the implicit script cache is correct.
1075 const int kExpectedNumResources = 2;
1076 int num_resources = 0;
1077 RunOnIOThread(
1078 base::Bind(&CountScriptResources,
1079 base::Unretained(wrapper()),
1080 embedded_test_server()->GetURL(kScopeUrl),
1081 &num_resources));
1082 EXPECT_EQ(kExpectedNumResources, num_resources);
1085 class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
1086 public:
1087 using self = ServiceWorkerBlackBoxBrowserTest;
1089 void FindRegistrationOnIO(const GURL& document_url,
1090 ServiceWorkerStatusCode* status,
1091 const base::Closure& continuation) {
1092 wrapper()->FindRegistrationForDocument(
1093 document_url,
1094 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
1095 this, status, continuation));
1098 void FindRegistrationOnIO2(
1099 ServiceWorkerStatusCode* out_status,
1100 const base::Closure& continuation,
1101 ServiceWorkerStatusCode status,
1102 const scoped_refptr<ServiceWorkerRegistration>& registration) {
1103 *out_status = status;
1104 if (!registration.get())
1105 EXPECT_NE(SERVICE_WORKER_OK, status);
1106 continuation.Run();
1110 static int CountRenderProcessHosts() {
1111 int result = 0;
1112 for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
1113 !iter.IsAtEnd();
1114 iter.Advance()) {
1115 result++;
1117 return result;
1120 // Flaky timeouts on CrOS: http://crbug.com/387045
1121 #if defined(OS_CHROMEOS)
1122 #define MAYBE_Registration DISABLED_Registration
1123 #else
1124 #define MAYBE_Registration Registration
1125 #endif
1126 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
1127 // Close the only window to be sure we're not re-using its RenderProcessHost.
1128 shell()->Close();
1129 EXPECT_EQ(0, CountRenderProcessHosts());
1131 const char kWorkerUrl[] = "/service_worker/fetch_event.js";
1132 const char kScope[] = "/service_worker/";
1134 // Unregistering nothing should return false.
1136 base::RunLoop run_loop;
1137 public_context()->UnregisterServiceWorker(
1138 embedded_test_server()->GetURL("/"),
1139 base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
1140 run_loop.Run();
1143 // If we use a worker URL that doesn't exist, registration fails.
1145 base::RunLoop run_loop;
1146 public_context()->RegisterServiceWorker(
1147 embedded_test_server()->GetURL(kScope),
1148 embedded_test_server()->GetURL("/does/not/exist"),
1149 base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
1150 run_loop.Run();
1152 EXPECT_EQ(0, CountRenderProcessHosts());
1154 // Register returns when the promise would be resolved.
1156 base::RunLoop run_loop;
1157 public_context()->RegisterServiceWorker(
1158 embedded_test_server()->GetURL(kScope),
1159 embedded_test_server()->GetURL(kWorkerUrl),
1160 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1161 run_loop.Run();
1163 EXPECT_EQ(1, CountRenderProcessHosts());
1165 // Registering again should succeed, although the algo still
1166 // might not be complete.
1168 base::RunLoop run_loop;
1169 public_context()->RegisterServiceWorker(
1170 embedded_test_server()->GetURL(kScope),
1171 embedded_test_server()->GetURL(kWorkerUrl),
1172 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1173 run_loop.Run();
1176 // The registration algo might not be far enough along to have
1177 // stored the registration data, so it may not be findable
1178 // at this point.
1180 // Unregistering something should return true.
1182 base::RunLoop run_loop;
1183 public_context()->UnregisterServiceWorker(
1184 embedded_test_server()->GetURL(kScope),
1185 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1186 run_loop.Run();
1188 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
1189 "workers eagerly, so their RPHs "
1190 "can still be running.";
1192 // Should not be able to find it.
1194 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
1195 RunOnIOThread(
1196 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
1197 this,
1198 embedded_test_server()->GetURL("/service_worker/empty.html"),
1199 &status));
1200 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
1204 #if defined(ANDROID)
1205 #define MAYBE_CrossSiteTransfer DISABLED_CrossSiteTransfer
1206 #else
1207 #define MAYBE_CrossSiteTransfer CrossSiteTransfer
1208 #endif
1209 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, MAYBE_CrossSiteTransfer) {
1210 // The first page registers a service worker.
1211 const char kRegisterPageUrl[] = "/service_worker/cross_site_xfer.html";
1212 const base::string16 kOKTitle1(base::ASCIIToUTF16("OK_1"));
1213 const base::string16 kFailTitle1(base::ASCIIToUTF16("FAIL_1"));
1214 content::TitleWatcher title_watcher1(shell()->web_contents(), kOKTitle1);
1215 title_watcher1.AlsoWaitForTitle(kFailTitle1);
1217 NavigateToURL(shell(), embedded_test_server()->GetURL(kRegisterPageUrl));
1218 ASSERT_EQ(kOKTitle1, title_watcher1.WaitAndGetTitle());
1220 // Force process swapping behavior.
1221 ShellContentBrowserClient::SetSwapProcessesForRedirect(true);
1223 // The second pages loads via the serviceworker including a subresource.
1224 const char kConfirmPageUrl[] =
1225 "/service_worker/cross_site_xfer_scope/"
1226 "cross_site_xfer_confirm_via_serviceworker.html";
1227 const base::string16 kOKTitle2(base::ASCIIToUTF16("OK_2"));
1228 const base::string16 kFailTitle2(base::ASCIIToUTF16("FAIL_2"));
1229 content::TitleWatcher title_watcher2(shell()->web_contents(), kOKTitle2);
1230 title_watcher2.AlsoWaitForTitle(kFailTitle2);
1232 NavigateToURL(shell(), embedded_test_server()->GetURL(kConfirmPageUrl));
1233 EXPECT_EQ(kOKTitle2, title_watcher2.WaitAndGetTitle());
1236 class ServiceWorkerVersionBrowserV8CacheTest
1237 : public ServiceWorkerVersionBrowserTest,
1238 public ServiceWorkerVersion::Listener {
1239 public:
1240 using self = ServiceWorkerVersionBrowserV8CacheTest;
1241 ~ServiceWorkerVersionBrowserV8CacheTest() override {
1242 if (version_)
1243 version_->RemoveListener(this);
1245 void SetUpCommandLine(base::CommandLine* command_line) override {
1246 ServiceWorkerBrowserTest::SetUpCommandLine(command_line);
1247 command_line->AppendSwitchASCII(switches::kV8CacheOptions, "code");
1249 void SetUpRegistrationAndListenerOnIOThread(const std::string& worker_url) {
1250 SetUpRegistrationOnIOThread(worker_url);
1251 version_->AddListener(this);
1254 protected:
1255 // ServiceWorkerVersion::Listener overrides
1256 void OnCachedMetadataUpdated(ServiceWorkerVersion* version) override {
1257 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1258 cache_updated_closure_);
1261 base::Closure cache_updated_closure_;
1264 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserV8CacheTest, Restart) {
1265 RunOnIOThread(base::Bind(&self::SetUpRegistrationAndListenerOnIOThread, this,
1266 "/service_worker/worker.js"));
1268 base::RunLoop cached_metadata_run_loop;
1269 cache_updated_closure_ = cached_metadata_run_loop.QuitClosure();
1271 // Start a worker.
1272 StartWorker(SERVICE_WORKER_OK);
1274 // Wait for the matadata is stored. This run loop should finish when
1275 // OnCachedMetadataUpdated() is called.
1276 cached_metadata_run_loop.Run();
1278 // Activate the worker.
1279 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
1280 base::RunLoop activate_run_loop;
1281 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1282 base::Bind(&self::ActivateOnIOThread, this,
1283 activate_run_loop.QuitClosure(), &status));
1284 activate_run_loop.Run();
1285 ASSERT_EQ(SERVICE_WORKER_OK, status);
1286 // Stop the worker.
1287 StopWorker(SERVICE_WORKER_OK);
1288 // Restart the worker.
1289 StartWorker(SERVICE_WORKER_OK);
1290 // Stop the worker.
1291 StopWorker(SERVICE_WORKER_OK);
1294 } // namespace content