Roll ANGLE e754fb8..6ffeb74
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_browsertest.cc
blob97723e136d2dbbb6bae593f85432ddba13d090c7
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 EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
345 public EmbeddedWorkerInstance::Listener {
346 public:
347 using self = EmbeddedWorkerBrowserTest;
349 EmbeddedWorkerBrowserTest()
350 : last_worker_status_(EmbeddedWorkerInstance::STOPPED),
351 pause_mode_(DONT_PAUSE) {}
352 ~EmbeddedWorkerBrowserTest() override {}
354 void TearDownOnIOThread() override {
355 if (worker_) {
356 worker_->RemoveListener(this);
357 if (worker_->status() == EmbeddedWorkerInstance::STARTING ||
358 worker_->status() == EmbeddedWorkerInstance::RUNNING) {
359 worker_->Stop();
361 worker_.reset();
365 void StartOnIOThread() {
366 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
367 worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
368 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
369 worker_->AddListener(this);
371 const int64 service_worker_version_id = 33L;
372 const GURL pattern = embedded_test_server()->GetURL("/");
373 const GURL script_url = embedded_test_server()->GetURL(
374 "/service_worker/worker.js");
375 AssociateRendererProcessToPattern(pattern);
376 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
377 wrapper()->process_manager()->AddProcessReferenceToPattern(
378 pattern, process_id);
379 worker_->Start(
380 service_worker_version_id,
381 pattern,
382 script_url,
383 pause_mode_ != DONT_PAUSE,
384 base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
386 void StartOnIOThread2(ServiceWorkerStatusCode status) {
387 last_worker_status_ = worker_->status();
388 EXPECT_EQ(SERVICE_WORKER_OK, status);
389 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
391 if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
392 done_closure_.Run();
395 void StopOnIOThread() {
396 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
397 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status());
399 ServiceWorkerStatusCode status = worker_->Stop();
401 last_worker_status_ = worker_->status();
402 EXPECT_EQ(SERVICE_WORKER_OK, status);
403 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_);
405 if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
406 done_closure_.Run();
409 protected:
410 // EmbeddedWorkerInstance::Observer overrides:
411 void OnStarted() override {
412 ASSERT_TRUE(worker_ != NULL);
413 ASSERT_FALSE(done_closure_.is_null());
414 last_worker_status_ = worker_->status();
415 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
417 void OnStopped(EmbeddedWorkerInstance::Status old_status) override {
418 ASSERT_TRUE(worker_ != NULL);
419 ASSERT_FALSE(done_closure_.is_null());
420 last_worker_status_ = worker_->status();
421 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
423 void OnPausedAfterDownload() override {
424 if (pause_mode_ == PAUSE_THEN_RESUME)
425 worker_->ResumeAfterDownload();
426 else if (pause_mode_ == PAUSE_THEN_STOP)
427 worker_->Stop();
428 else
429 ASSERT_TRUE(false);
431 void OnReportException(const base::string16& error_message,
432 int line_number,
433 int column_number,
434 const GURL& source_url) override {}
435 void OnReportConsoleMessage(int source_identifier,
436 int message_level,
437 const base::string16& message,
438 int line_number,
439 const GURL& source_url) override {}
440 bool OnMessageReceived(const IPC::Message& message) override { return false; }
442 scoped_ptr<EmbeddedWorkerInstance> worker_;
443 EmbeddedWorkerInstance::Status last_worker_status_;
445 enum {
446 DONT_PAUSE,
447 PAUSE_THEN_RESUME,
448 PAUSE_THEN_STOP,
449 } pause_mode_;
451 // Called by EmbeddedWorkerInstance::Observer overrides so that
452 // test code can wait for the worker status notifications.
453 base::Closure done_closure_;
456 class ConsoleListener : public EmbeddedWorkerInstance::Listener {
457 public:
458 void OnReportConsoleMessage(int source_identifier,
459 int message_level,
460 const base::string16& message,
461 int line_number,
462 const GURL& source_url) override {
463 messages_.push_back(message);
464 if (!quit_.is_null() && messages_.size() == expected_message_count_) {
465 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_);
466 quit_.Reset();
470 void WaitForConsoleMessages(size_t expected_message_count) {
471 if (messages_.size() >= expected_message_count)
472 return;
474 expected_message_count_ = expected_message_count;
475 base::RunLoop console_run_loop;
476 quit_ = console_run_loop.QuitClosure();
477 console_run_loop.Run();
479 ASSERT_EQ(messages_.size(), expected_message_count);
482 bool OnMessageReceived(const IPC::Message& message) override { return false; }
483 const std::vector<base::string16>& messages() const { return messages_; }
485 private:
486 std::vector<base::string16> messages_;
487 size_t expected_message_count_;
488 base::Closure quit_;
491 class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
492 public:
493 using self = ServiceWorkerVersionBrowserTest;
495 ~ServiceWorkerVersionBrowserTest() override {}
497 void TearDownOnIOThread() override {
498 registration_ = NULL;
499 version_ = NULL;
502 void InstallTestHelper(const std::string& worker_url,
503 ServiceWorkerStatusCode expected_status) {
504 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
505 worker_url));
507 // Dispatch install on a worker.
508 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
509 base::RunLoop install_run_loop;
510 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
511 base::Bind(&self::InstallOnIOThread, this,
512 install_run_loop.QuitClosure(),
513 &status));
514 install_run_loop.Run();
515 ASSERT_EQ(expected_status, status);
517 // Stop the worker.
518 status = SERVICE_WORKER_ERROR_FAILED;
519 base::RunLoop stop_run_loop;
520 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
521 base::Bind(&self::StopOnIOThread, this,
522 stop_run_loop.QuitClosure(),
523 &status));
524 stop_run_loop.Run();
525 ASSERT_EQ(SERVICE_WORKER_OK, status);
528 void ActivateTestHelper(
529 const std::string& worker_url,
530 ServiceWorkerStatusCode expected_status) {
531 RunOnIOThread(
532 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
533 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
534 base::RunLoop run_loop;
535 BrowserThread::PostTask(
536 BrowserThread::IO,
537 FROM_HERE,
538 base::Bind(
539 &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status));
540 run_loop.Run();
541 ASSERT_EQ(expected_status, status);
544 void FetchOnRegisteredWorker(
545 ServiceWorkerFetchEventResult* result,
546 ServiceWorkerResponse* response,
547 scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
548 blob_context_ = ChromeBlobStorageContext::GetFor(
549 shell()->web_contents()->GetBrowserContext());
550 bool prepare_result = false;
551 FetchResult fetch_result;
552 fetch_result.status = SERVICE_WORKER_ERROR_FAILED;
553 base::RunLoop fetch_run_loop;
554 BrowserThread::PostTask(BrowserThread::IO,
555 FROM_HERE,
556 base::Bind(&self::FetchOnIOThread,
557 this,
558 fetch_run_loop.QuitClosure(),
559 &prepare_result,
560 &fetch_result));
561 fetch_run_loop.Run();
562 ASSERT_TRUE(prepare_result);
563 *result = fetch_result.result;
564 *response = fetch_result.response;
565 *blob_data_handle = fetch_result.blob_data_handle.Pass();
566 ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status);
569 void FetchTestHelper(const std::string& worker_url,
570 ServiceWorkerFetchEventResult* result,
571 ServiceWorkerResponse* response,
572 scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
573 RunOnIOThread(
574 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
575 FetchOnRegisteredWorker(result, response, blob_data_handle);
578 void SetUpRegistrationOnIOThread(const std::string& worker_url) {
579 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
580 const GURL pattern = embedded_test_server()->GetURL("/service_worker/");
581 registration_ = new ServiceWorkerRegistration(
582 pattern,
583 wrapper()->context()->storage()->NewRegistrationId(),
584 wrapper()->context()->AsWeakPtr());
585 version_ = new ServiceWorkerVersion(
586 registration_.get(),
587 embedded_test_server()->GetURL(worker_url),
588 wrapper()->context()->storage()->NewVersionId(),
589 wrapper()->context()->AsWeakPtr());
591 // Make the registration findable via storage functions.
592 wrapper()->context()->storage()->NotifyInstallingRegistration(
593 registration_.get());
595 AssociateRendererProcessToPattern(pattern);
598 void TimeoutWorkerOnIOThread() {
599 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
600 version_->SimulatePingTimeoutForTesting();
603 void AddControlleeOnIOThread() {
604 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
605 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
606 33 /* dummy render process id */,
607 MSG_ROUTING_NONE /* render_frame_id */, 1 /* dummy provider_id */,
608 SERVICE_WORKER_PROVIDER_FOR_WINDOW, wrapper()->context()->AsWeakPtr(),
609 NULL));
610 host->SetDocumentUrl(
611 embedded_test_server()->GetURL("/service_worker/host"));
612 host->AssociateRegistration(registration_.get(),
613 false /* notify_controllerchange */);
614 wrapper()->context()->AddProviderHost(host.Pass());
617 void AddWaitingWorkerOnIOThread(const std::string& worker_url) {
618 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
619 scoped_refptr<ServiceWorkerVersion> waiting_version(
620 new ServiceWorkerVersion(
621 registration_.get(), embedded_test_server()->GetURL(worker_url),
622 wrapper()->context()->storage()->NewVersionId(),
623 wrapper()->context()->AsWeakPtr()));
624 waiting_version->SetStatus(ServiceWorkerVersion::INSTALLED);
625 registration_->SetWaitingVersion(waiting_version.get());
626 registration_->ActivateWaitingVersionWhenReady();
629 void StartWorker(ServiceWorkerStatusCode expected_status) {
630 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
631 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
632 base::RunLoop start_run_loop;
633 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
634 base::Bind(&self::StartOnIOThread, this,
635 start_run_loop.QuitClosure(),
636 &status));
637 start_run_loop.Run();
638 ASSERT_EQ(expected_status, status);
641 void StopWorker(ServiceWorkerStatusCode expected_status) {
642 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
643 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
644 base::RunLoop stop_run_loop;
645 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
646 base::Bind(&self::StopOnIOThread, this,
647 stop_run_loop.QuitClosure(),
648 &status));
649 stop_run_loop.Run();
650 ASSERT_EQ(expected_status, status);
653 void StoreRegistration(int64 version_id,
654 ServiceWorkerStatusCode expected_status) {
655 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
656 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
657 base::RunLoop store_run_loop;
658 BrowserThread::PostTask(
659 BrowserThread::IO, FROM_HERE,
660 base::Bind(&self::StoreOnIOThread, this, store_run_loop.QuitClosure(),
661 &status, version_id));
662 store_run_loop.Run();
663 ASSERT_EQ(expected_status, status);
665 RunOnIOThread(base::Bind(&self::NotifyDoneInstallingRegistrationOnIOThread,
666 this, status));
669 void FindRegistrationForId(int64 id,
670 const GURL& origin,
671 ServiceWorkerStatusCode expected_status) {
672 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
673 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
674 base::RunLoop run_loop;
675 BrowserThread::PostTask(
676 BrowserThread::IO, FROM_HERE,
677 base::Bind(&self::FindRegistrationForIdOnIOThread, this,
678 run_loop.QuitClosure(), &status, id, origin));
679 run_loop.Run();
680 ASSERT_EQ(expected_status, status);
683 void FindRegistrationForIdOnIOThread(const base::Closure& done,
684 ServiceWorkerStatusCode* result,
685 int64 id,
686 const GURL& origin) {
687 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
688 wrapper()->context()->storage()->FindRegistrationForId(
689 id, origin,
690 CreateFindRegistrationReceiver(BrowserThread::UI, done, result));
693 void NotifyDoneInstallingRegistrationOnIOThread(
694 ServiceWorkerStatusCode status) {
695 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
696 wrapper()->context()->storage()->NotifyDoneInstallingRegistration(
697 registration_.get(), version_.get(), status);
700 void RemoveLiveRegistrationOnIOThread(int64 id) {
701 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
702 wrapper()->context()->RemoveLiveRegistration(id);
705 void StartOnIOThread(const base::Closure& done,
706 ServiceWorkerStatusCode* result) {
707 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
708 version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result));
711 void InstallOnIOThread(const base::Closure& done,
712 ServiceWorkerStatusCode* result) {
713 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
714 version_->SetStatus(ServiceWorkerVersion::INSTALLING);
715 version_->DispatchInstallEvent(
716 CreateReceiver(BrowserThread::UI, done, result));
719 void StoreOnIOThread(const base::Closure& done,
720 ServiceWorkerStatusCode* result,
721 int64 version_id) {
722 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
723 ServiceWorkerVersion* version =
724 wrapper()->context()->GetLiveVersion(version_id);
725 wrapper()->context()->storage()->StoreRegistration(
726 registration_.get(), version,
727 CreateReceiver(BrowserThread::UI, done, result));
730 void ActivateOnIOThread(const base::Closure& done,
731 ServiceWorkerStatusCode* result) {
732 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
733 version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
734 registration_->SetActiveVersion(version_.get());
735 version_->DispatchActivateEvent(
736 CreateReceiver(BrowserThread::UI, done, result));
739 void FetchOnIOThread(const base::Closure& done,
740 bool* prepare_result,
741 FetchResult* result) {
742 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
743 ServiceWorkerFetchRequest request(
744 embedded_test_server()->GetURL("/service_worker/empty.html"),
745 "GET",
746 ServiceWorkerHeaderMap(),
747 Referrer(),
748 false);
749 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
750 version_->DispatchFetchEvent(
751 request,
752 CreatePrepareReceiver(prepare_result),
753 CreateResponseReceiver(
754 BrowserThread::UI, done, blob_context_.get(), result));
757 void StopOnIOThread(const base::Closure& done,
758 ServiceWorkerStatusCode* result) {
759 ASSERT_TRUE(version_.get());
760 version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
763 void SyncEventOnIOThread(const base::Closure& done,
764 ServiceWorkerStatusCode* result) {
765 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
766 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
767 version_->DispatchSyncEvent(
768 CreateReceiver(BrowserThread::UI, done, result));
771 protected:
772 scoped_refptr<ServiceWorkerRegistration> registration_;
773 scoped_refptr<ServiceWorkerVersion> version_;
774 scoped_refptr<ChromeBlobStorageContext> blob_context_;
777 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
778 // Start a worker and wait until OnStarted() is called.
779 base::RunLoop start_run_loop;
780 done_closure_ = start_run_loop.QuitClosure();
781 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
782 base::Bind(&self::StartOnIOThread, this));
783 start_run_loop.Run();
785 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
787 // Stop a worker and wait until OnStopped() is called.
788 base::RunLoop stop_run_loop;
789 done_closure_ = stop_run_loop.QuitClosure();
790 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
791 base::Bind(&self::StopOnIOThread, this));
792 stop_run_loop.Run();
794 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
797 #if defined(OS_LINUX)
798 // Flaky on Linux 32-bit: http://crbug.com/498688.
799 #define MAYBE_StartPaused_ThenResume DISABLED_StartPaused_ThenResume
800 #else
801 #define MAYBE_StartPaused_ThenResume StartPaused_ThenResume
802 #endif
803 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
804 MAYBE_StartPaused_ThenResume) {
805 pause_mode_ = PAUSE_THEN_RESUME;
806 base::RunLoop start_run_loop;
807 done_closure_ = start_run_loop.QuitClosure();
808 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
809 base::Bind(&self::StartOnIOThread, this));
810 start_run_loop.Run();
811 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
814 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
815 StartPaused_ThenStop) {
816 pause_mode_ = PAUSE_THEN_STOP;
817 base::RunLoop start_run_loop;
818 done_closure_ = start_run_loop.QuitClosure();
819 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
820 base::Bind(&self::StartOnIOThread, this));
821 start_run_loop.Run();
822 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
825 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
826 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
827 "/service_worker/worker.js"));
829 // Start a worker.
830 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
831 base::RunLoop start_run_loop;
832 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
833 base::Bind(&self::StartOnIOThread, this,
834 start_run_loop.QuitClosure(),
835 &status));
836 start_run_loop.Run();
837 ASSERT_EQ(SERVICE_WORKER_OK, status);
839 // Stop the worker.
840 status = SERVICE_WORKER_ERROR_FAILED;
841 base::RunLoop stop_run_loop;
842 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
843 base::Bind(&self::StopOnIOThread, this,
844 stop_run_loop.QuitClosure(),
845 &status));
846 stop_run_loop.Run();
847 ASSERT_EQ(SERVICE_WORKER_OK, status);
850 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
851 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
852 "/service_worker/nonexistent.js"));
854 // Start a worker for nonexistent URL.
855 StartWorker(SERVICE_WORKER_ERROR_NETWORK);
858 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, ReadResourceFailure) {
859 // Create a registration.
860 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
861 "/service_worker/worker.js"));
862 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
864 // Add a non-existent resource to the version.
865 std::vector<ServiceWorkerDatabase::ResourceRecord> records;
866 records.push_back(
867 ServiceWorkerDatabase::ResourceRecord(30, version_->script_url(), 100));
868 version_->script_cache_map()->SetResources(records);
870 // Store the registration.
871 StoreRegistration(version_->version_id(), SERVICE_WORKER_OK);
873 // Start the worker. We'll fail to read the resource.
874 StartWorker(SERVICE_WORKER_ERROR_DISK_CACHE);
875 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version_->status());
877 // The registration should be deleted from storage since the broken worker was
878 // the stored one.
879 RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread, this,
880 registration_->id()));
881 FindRegistrationForId(registration_->id(),
882 registration_->pattern().GetOrigin(),
883 SERVICE_WORKER_ERROR_NOT_FOUND);
886 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
887 ReadResourceFailure_WaitingWorker) {
888 // Create a registration and active version.
889 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
890 "/service_worker/worker.js"));
891 base::RunLoop activate_run_loop;
892 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
893 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
894 base::Bind(&self::ActivateOnIOThread, this,
895 activate_run_loop.QuitClosure(), &status));
896 activate_run_loop.Run();
897 EXPECT_EQ(SERVICE_WORKER_OK, status);
898 ASSERT_TRUE(registration_->active_version());
900 // Give the version a controllee.
901 RunOnIOThread(base::Bind(&self::AddControlleeOnIOThread, this));
903 // Add a non-existent resource to the version.
904 std::vector<ServiceWorkerDatabase::ResourceRecord> records;
905 records.push_back(
906 ServiceWorkerDatabase::ResourceRecord(30, version_->script_url(), 100));
907 version_->script_cache_map()->SetResources(records);
909 // Make a waiting version and store it.
910 RunOnIOThread(base::Bind(&self::AddWaitingWorkerOnIOThread, this,
911 "/service_worker/worker.js"));
912 registration_->waiting_version()->script_cache_map()->SetResources(records);
913 StoreRegistration(registration_->waiting_version()->version_id(),
914 SERVICE_WORKER_OK);
916 // Start the broken worker. We'll fail to read from disk and the worker should
917 // be doomed.
918 StopWorker(SERVICE_WORKER_OK); // in case it's already running
919 StartWorker(SERVICE_WORKER_ERROR_DISK_CACHE);
920 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version_->status());
922 // The registration should still be in storage since the waiting worker was
923 // the stored one.
924 RunOnIOThread(base::Bind(&self::RemoveLiveRegistrationOnIOThread, this,
925 registration_->id()));
926 FindRegistrationForId(registration_->id(),
927 registration_->pattern().GetOrigin(),
928 SERVICE_WORKER_OK);
931 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
932 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
935 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
936 InstallWithWaitUntil_Fulfilled) {
937 InstallTestHelper("/service_worker/worker_install_fulfilled.js",
938 SERVICE_WORKER_OK);
941 // Check that ServiceWorker script requests set a "Service-Worker: script"
942 // header.
943 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
944 ServiceWorkerScriptHeader) {
945 embedded_test_server()->RegisterRequestHandler(
946 base::Bind(&VerifyServiceWorkerHeaderInRequest));
947 InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
950 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
951 Activate_NoEventListener) {
952 ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
953 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
956 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
957 ActivateTestHelper("/service_worker/worker_activate_rejected.js",
958 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
961 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
962 InstallWithWaitUntil_Rejected) {
963 InstallTestHelper("/service_worker/worker_install_rejected.js",
964 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
967 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
968 InstallWithWaitUntil_RejectConsoleMessage) {
969 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
970 "/service_worker/worker_install_rejected.js"));
972 ConsoleListener console_listener;
973 version_->embedded_worker()->AddListener(&console_listener);
975 // Dispatch install on a worker.
976 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
977 base::RunLoop install_run_loop;
978 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
979 base::Bind(&self::InstallOnIOThread, this,
980 install_run_loop.QuitClosure(), &status));
981 install_run_loop.Run();
982 ASSERT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, status);
984 const base::string16 expected =
985 base::ASCIIToUTF16("Rejecting oninstall event");
986 console_listener.WaitForConsoleMessages(1);
987 ASSERT_NE(base::string16::npos,
988 console_listener.messages()[0].find(expected));
989 version_->embedded_worker()->RemoveListener(&console_listener);
992 class WaitForLoaded : public EmbeddedWorkerInstance::Listener {
993 public:
994 WaitForLoaded(const base::Closure& quit) : quit_(quit) {}
996 void OnScriptLoaded() override {
997 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_);
999 bool OnMessageReceived(const IPC::Message& message) override { return false; }
1001 private:
1002 base::Closure quit_;
1005 // This test has started flaking somewhat consistently on Win, Mac and Linux.
1006 // Disabling for now, see http://crbug.com/496065.
1007 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
1008 DISABLED_TimeoutStartingWorker) {
1009 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
1010 "/service_worker/while_true_worker.js"));
1012 // Start a worker, waiting until the script is loaded.
1013 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
1014 base::RunLoop start_run_loop;
1015 base::RunLoop load_run_loop;
1016 WaitForLoaded wait_for_load(load_run_loop.QuitClosure());
1017 version_->embedded_worker()->AddListener(&wait_for_load);
1018 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1019 base::Bind(&self::StartOnIOThread, this,
1020 start_run_loop.QuitClosure(), &status));
1021 load_run_loop.Run();
1022 version_->embedded_worker()->RemoveListener(&wait_for_load);
1024 // The script has loaded but start has not completed yet.
1025 ASSERT_EQ(SERVICE_WORKER_ERROR_FAILED, status);
1026 EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
1028 // Simulate execution timeout. Use a delay to prevent killing the worker
1029 // before it's started execution.
1030 EXPECT_TRUE(version_->timeout_timer_.IsRunning());
1031 RunOnIOThreadWithDelay(base::Bind(&self::TimeoutWorkerOnIOThread, this),
1032 base::TimeDelta::FromMilliseconds(100));
1033 start_run_loop.Run();
1035 EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
1038 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, TimeoutWorkerInEvent) {
1039 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
1040 "/service_worker/while_true_in_install_worker.js"));
1042 // Start a worker.
1043 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
1044 base::RunLoop start_run_loop;
1045 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1046 base::Bind(&self::StartOnIOThread, this,
1047 start_run_loop.QuitClosure(), &status));
1048 start_run_loop.Run();
1049 ASSERT_EQ(SERVICE_WORKER_OK, status);
1051 // Dispatch an event.
1052 base::RunLoop install_run_loop;
1053 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1054 base::Bind(&self::InstallOnIOThread, this,
1055 install_run_loop.QuitClosure(), &status));
1057 // Simulate execution timeout. Use a delay to prevent killing the worker
1058 // before it's started execution.
1059 EXPECT_TRUE(version_->timeout_timer_.IsRunning());
1060 RunOnIOThreadWithDelay(base::Bind(&self::TimeoutWorkerOnIOThread, this),
1061 base::TimeDelta::FromMilliseconds(100));
1062 install_run_loop.Run();
1064 EXPECT_EQ(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED, status);
1067 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
1068 ServiceWorkerFetchEventResult result;
1069 ServiceWorkerResponse response;
1070 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
1071 FetchTestHelper("/service_worker/fetch_event.js",
1072 &result, &response, &blob_data_handle);
1073 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
1074 EXPECT_EQ(301, response.status_code);
1075 EXPECT_EQ("Moved Permanently", response.status_text);
1076 ServiceWorkerHeaderMap expected_headers;
1077 expected_headers["content-language"] = "fi";
1078 expected_headers["content-type"] = "text/html; charset=UTF-8";
1079 EXPECT_EQ(expected_headers, response.headers);
1081 std::string body;
1082 RunOnIOThread(
1083 base::Bind(&ReadResponseBody,
1084 &body, base::Owned(blob_data_handle.release())));
1085 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body);
1088 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
1089 FetchEvent_respondWithRejection) {
1090 ServiceWorkerFetchEventResult result;
1091 ServiceWorkerResponse response;
1092 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
1094 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
1095 "/service_worker/fetch_event_rejected.js"));
1097 ConsoleListener console_listener;
1098 version_->embedded_worker()->AddListener(&console_listener);
1100 FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
1101 const base::string16 expected =
1102 base::ASCIIToUTF16("Rejecting respondWith promise");
1103 console_listener.WaitForConsoleMessages(1);
1104 ASSERT_NE(base::string16::npos,
1105 console_listener.messages()[0].find(expected));
1106 version_->embedded_worker()->RemoveListener(&console_listener);
1108 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
1109 EXPECT_EQ(0, response.status_code);
1111 ASSERT_FALSE(blob_data_handle);
1114 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
1115 SyncAbortedWithoutFlag) {
1116 RunOnIOThread(base::Bind(
1117 &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
1119 // Run the sync event.
1120 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
1121 base::RunLoop sync_run_loop;
1122 BrowserThread::PostTask(BrowserThread::IO,
1123 FROM_HERE,
1124 base::Bind(&self::SyncEventOnIOThread,
1125 this,
1126 sync_run_loop.QuitClosure(),
1127 &status));
1128 sync_run_loop.Run();
1129 ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
1132 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
1133 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1134 command_line->AppendSwitch(switches::kEnableServiceWorkerSync);
1136 RunOnIOThread(base::Bind(
1137 &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
1138 ServiceWorkerFetchEventResult result;
1139 ServiceWorkerResponse response;
1140 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
1141 // Should 404 before sync event.
1142 FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
1143 EXPECT_EQ(404, response.status_code);
1145 // Run the sync event.
1146 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
1147 base::RunLoop sync_run_loop;
1148 BrowserThread::PostTask(BrowserThread::IO,
1149 FROM_HERE,
1150 base::Bind(&self::SyncEventOnIOThread,
1151 this,
1152 sync_run_loop.QuitClosure(),
1153 &status));
1154 sync_run_loop.Run();
1155 ASSERT_EQ(SERVICE_WORKER_OK, status);
1157 // Should 200 after sync event.
1158 FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
1159 EXPECT_EQ(200, response.status_code);
1162 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, Reload) {
1163 const char kPageUrl[] = "/service_worker/reload.html";
1164 const char kWorkerUrl[] = "/service_worker/fetch_event_reload.js";
1165 scoped_refptr<WorkerActivatedObserver> observer =
1166 new WorkerActivatedObserver(wrapper());
1167 observer->Init();
1168 public_context()->RegisterServiceWorker(
1169 embedded_test_server()->GetURL(kPageUrl),
1170 embedded_test_server()->GetURL(kWorkerUrl),
1171 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
1172 observer->Wait();
1174 const base::string16 title1 = base::ASCIIToUTF16("reload=false");
1175 TitleWatcher title_watcher1(shell()->web_contents(), title1);
1176 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
1177 EXPECT_EQ(title1, title_watcher1.WaitAndGetTitle());
1179 const base::string16 title2 = base::ASCIIToUTF16("reload=true");
1180 TitleWatcher title_watcher2(shell()->web_contents(), title2);
1181 ReloadBlockUntilNavigationsComplete(shell(), 1);
1182 EXPECT_EQ(title2, title_watcher2.WaitAndGetTitle());
1184 shell()->Close();
1186 base::RunLoop run_loop;
1187 public_context()->UnregisterServiceWorker(
1188 embedded_test_server()->GetURL(kPageUrl),
1189 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1190 run_loop.Run();
1193 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
1194 ResponseFromHTTPSServiceWorkerIsMarkedAsSecure) {
1195 const char kPageUrl[] = "files/service_worker/fetch_event_blob.html";
1196 const char kWorkerUrl[] = "files/service_worker/fetch_event_blob.js";
1197 net::SpawnedTestServer https_server(
1198 net::SpawnedTestServer::TYPE_HTTPS,
1199 net::BaseTestServer::SSLOptions(
1200 net::BaseTestServer::SSLOptions::CERT_OK),
1201 base::FilePath(FILE_PATH_LITERAL("content/test/data/")));
1202 ASSERT_TRUE(https_server.Start());
1204 scoped_refptr<WorkerActivatedObserver> observer =
1205 new WorkerActivatedObserver(wrapper());
1206 observer->Init();
1207 public_context()->RegisterServiceWorker(
1208 https_server.GetURL(kPageUrl),
1209 https_server.GetURL(kWorkerUrl),
1210 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
1211 observer->Wait();
1213 const base::string16 title = base::ASCIIToUTF16("Title");
1214 TitleWatcher title_watcher(shell()->web_contents(), title);
1215 NavigateToURL(shell(), https_server.GetURL(kPageUrl));
1216 EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
1217 EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
1218 NavigationEntry* entry =
1219 shell()->web_contents()->GetController().GetVisibleEntry();
1220 EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, entry->GetSSL().security_style);
1222 shell()->Close();
1224 base::RunLoop run_loop;
1225 public_context()->UnregisterServiceWorker(
1226 https_server.GetURL(kPageUrl),
1227 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1228 run_loop.Run();
1231 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
1232 ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure) {
1233 const char kPageUrl[] = "/service_worker/fetch_event_blob.html";
1234 const char kWorkerUrl[] = "/service_worker/fetch_event_blob.js";
1235 scoped_refptr<WorkerActivatedObserver> observer =
1236 new WorkerActivatedObserver(wrapper());
1237 observer->Init();
1238 public_context()->RegisterServiceWorker(
1239 embedded_test_server()->GetURL(kPageUrl),
1240 embedded_test_server()->GetURL(kWorkerUrl),
1241 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
1242 observer->Wait();
1244 const base::string16 title = base::ASCIIToUTF16("Title");
1245 TitleWatcher title_watcher(shell()->web_contents(), title);
1246 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
1247 EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
1248 EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
1249 NavigationEntry* entry =
1250 shell()->web_contents()->GetController().GetVisibleEntry();
1251 EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, entry->GetSSL().security_style);
1253 shell()->Close();
1255 base::RunLoop run_loop;
1256 public_context()->UnregisterServiceWorker(
1257 embedded_test_server()->GetURL(kPageUrl),
1258 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1259 run_loop.Run();
1262 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
1263 const char kScopeUrl[] = "/service_worker/imports_bust_memcache_scope/";
1264 const char kPageUrl[] = "/service_worker/imports_bust_memcache.html";
1265 const char kScriptUrl[] = "/service_worker/worker_with_one_import.js";
1266 const char kImportUrl[] = "/service_worker/long_lived_import.js";
1267 const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
1268 const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
1270 RunOnIOThread(
1271 base::Bind(&CreateLongLivedResourceInterceptors,
1272 embedded_test_server()->GetURL(kScriptUrl),
1273 embedded_test_server()->GetURL(kImportUrl)));
1275 TitleWatcher title_watcher(shell()->web_contents(), kOKTitle);
1276 title_watcher.AlsoWaitForTitle(kFailTitle);
1277 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
1278 base::string16 title = title_watcher.WaitAndGetTitle();
1279 EXPECT_EQ(kOKTitle, title);
1281 // Verify the number of resources in the implicit script cache is correct.
1282 const int kExpectedNumResources = 2;
1283 int num_resources = 0;
1284 RunOnIOThread(
1285 base::Bind(&CountScriptResources,
1286 base::Unretained(wrapper()),
1287 embedded_test_server()->GetURL(kScopeUrl),
1288 &num_resources));
1289 EXPECT_EQ(kExpectedNumResources, num_resources);
1292 class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
1293 public:
1294 using self = ServiceWorkerBlackBoxBrowserTest;
1296 void FindRegistrationOnIO(const GURL& document_url,
1297 ServiceWorkerStatusCode* status,
1298 const base::Closure& continuation) {
1299 wrapper()->FindRegistrationForDocument(
1300 document_url,
1301 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
1302 this, status, continuation));
1305 void FindRegistrationOnIO2(
1306 ServiceWorkerStatusCode* out_status,
1307 const base::Closure& continuation,
1308 ServiceWorkerStatusCode status,
1309 const scoped_refptr<ServiceWorkerRegistration>& registration) {
1310 *out_status = status;
1311 if (!registration.get())
1312 EXPECT_NE(SERVICE_WORKER_OK, status);
1313 continuation.Run();
1317 static int CountRenderProcessHosts() {
1318 int result = 0;
1319 for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
1320 !iter.IsAtEnd();
1321 iter.Advance()) {
1322 result++;
1324 return result;
1327 // Flaky timeouts on CrOS: http://crbug.com/387045
1328 #if defined(OS_CHROMEOS)
1329 #define MAYBE_Registration DISABLED_Registration
1330 #else
1331 #define MAYBE_Registration Registration
1332 #endif
1333 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
1334 // Close the only window to be sure we're not re-using its RenderProcessHost.
1335 shell()->Close();
1336 EXPECT_EQ(0, CountRenderProcessHosts());
1338 const char kWorkerUrl[] = "/service_worker/fetch_event.js";
1339 const char kScope[] = "/service_worker/";
1341 // Unregistering nothing should return false.
1343 base::RunLoop run_loop;
1344 public_context()->UnregisterServiceWorker(
1345 embedded_test_server()->GetURL("/"),
1346 base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
1347 run_loop.Run();
1350 // If we use a worker URL that doesn't exist, registration fails.
1352 base::RunLoop run_loop;
1353 public_context()->RegisterServiceWorker(
1354 embedded_test_server()->GetURL(kScope),
1355 embedded_test_server()->GetURL("/does/not/exist"),
1356 base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
1357 run_loop.Run();
1359 EXPECT_EQ(0, CountRenderProcessHosts());
1361 // Register returns when the promise would be resolved.
1363 base::RunLoop run_loop;
1364 public_context()->RegisterServiceWorker(
1365 embedded_test_server()->GetURL(kScope),
1366 embedded_test_server()->GetURL(kWorkerUrl),
1367 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1368 run_loop.Run();
1370 EXPECT_EQ(1, CountRenderProcessHosts());
1372 // Registering again should succeed, although the algo still
1373 // might not be complete.
1375 base::RunLoop run_loop;
1376 public_context()->RegisterServiceWorker(
1377 embedded_test_server()->GetURL(kScope),
1378 embedded_test_server()->GetURL(kWorkerUrl),
1379 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1380 run_loop.Run();
1383 // The registration algo might not be far enough along to have
1384 // stored the registration data, so it may not be findable
1385 // at this point.
1387 // Unregistering something should return true.
1389 base::RunLoop run_loop;
1390 public_context()->UnregisterServiceWorker(
1391 embedded_test_server()->GetURL(kScope),
1392 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
1393 run_loop.Run();
1395 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
1396 "workers eagerly, so their RPHs "
1397 "can still be running.";
1399 // Should not be able to find it.
1401 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
1402 RunOnIOThread(
1403 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
1404 this,
1405 embedded_test_server()->GetURL("/service_worker/empty.html"),
1406 &status));
1407 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
1411 #if defined(ANDROID)
1412 #define MAYBE_CrossSiteTransfer DISABLED_CrossSiteTransfer
1413 #else
1414 #define MAYBE_CrossSiteTransfer CrossSiteTransfer
1415 #endif
1416 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, MAYBE_CrossSiteTransfer) {
1417 // The first page registers a service worker.
1418 const char kRegisterPageUrl[] = "/service_worker/cross_site_xfer.html";
1419 const base::string16 kOKTitle1(base::ASCIIToUTF16("OK_1"));
1420 const base::string16 kFailTitle1(base::ASCIIToUTF16("FAIL_1"));
1421 content::TitleWatcher title_watcher1(shell()->web_contents(), kOKTitle1);
1422 title_watcher1.AlsoWaitForTitle(kFailTitle1);
1424 NavigateToURL(shell(), embedded_test_server()->GetURL(kRegisterPageUrl));
1425 ASSERT_EQ(kOKTitle1, title_watcher1.WaitAndGetTitle());
1427 // Force process swapping behavior.
1428 ShellContentBrowserClient::SetSwapProcessesForRedirect(true);
1430 // The second pages loads via the serviceworker including a subresource.
1431 const char kConfirmPageUrl[] =
1432 "/service_worker/cross_site_xfer_scope/"
1433 "cross_site_xfer_confirm_via_serviceworker.html";
1434 const base::string16 kOKTitle2(base::ASCIIToUTF16("OK_2"));
1435 const base::string16 kFailTitle2(base::ASCIIToUTF16("FAIL_2"));
1436 content::TitleWatcher title_watcher2(shell()->web_contents(), kOKTitle2);
1437 title_watcher2.AlsoWaitForTitle(kFailTitle2);
1439 NavigateToURL(shell(), embedded_test_server()->GetURL(kConfirmPageUrl));
1440 EXPECT_EQ(kOKTitle2, title_watcher2.WaitAndGetTitle());
1443 class ServiceWorkerVersionBrowserV8CacheTest
1444 : public ServiceWorkerVersionBrowserTest,
1445 public ServiceWorkerVersion::Listener {
1446 public:
1447 using self = ServiceWorkerVersionBrowserV8CacheTest;
1448 ~ServiceWorkerVersionBrowserV8CacheTest() override {
1449 if (version_)
1450 version_->RemoveListener(this);
1452 void SetUpCommandLine(base::CommandLine* command_line) override {
1453 ServiceWorkerBrowserTest::SetUpCommandLine(command_line);
1454 command_line->AppendSwitchASCII(switches::kV8CacheOptions, "code");
1456 void SetUpRegistrationAndListenerOnIOThread(const std::string& worker_url) {
1457 SetUpRegistrationOnIOThread(worker_url);
1458 version_->AddListener(this);
1461 protected:
1462 // ServiceWorkerVersion::Listener overrides
1463 void OnCachedMetadataUpdated(ServiceWorkerVersion* version) override {
1464 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1465 cache_updated_closure_);
1468 base::Closure cache_updated_closure_;
1471 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserV8CacheTest, Restart) {
1472 RunOnIOThread(base::Bind(&self::SetUpRegistrationAndListenerOnIOThread, this,
1473 "/service_worker/worker.js"));
1475 base::RunLoop cached_metadata_run_loop;
1476 cache_updated_closure_ = cached_metadata_run_loop.QuitClosure();
1478 // Start a worker.
1479 StartWorker(SERVICE_WORKER_OK);
1481 // Wait for the matadata is stored. This run loop should finish when
1482 // OnCachedMetadataUpdated() is called.
1483 cached_metadata_run_loop.Run();
1485 // Activate the worker.
1486 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
1487 base::RunLoop activate_run_loop;
1488 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1489 base::Bind(&self::ActivateOnIOThread, this,
1490 activate_run_loop.QuitClosure(), &status));
1491 activate_run_loop.Run();
1492 ASSERT_EQ(SERVICE_WORKER_OK, status);
1493 // Stop the worker.
1494 StopWorker(SERVICE_WORKER_OK);
1495 // Restart the worker.
1496 StartWorker(SERVICE_WORKER_OK);
1497 // Stop the worker.
1498 StopWorker(SERVICE_WORKER_OK);
1501 } // namespace content