Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_browsertest.cc
blob0a67c1022061fb6e6c9e97c28374659644780963
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/strings/utf_string_conversions.h"
10 #include "content/browser/fileapi/chrome_blob_storage_context.h"
11 #include "content/browser/service_worker/embedded_worker_instance.h"
12 #include "content/browser/service_worker/embedded_worker_registry.h"
13 #include "content/browser/service_worker/service_worker_context_core.h"
14 #include "content/browser/service_worker/service_worker_context_observer.h"
15 #include "content/browser/service_worker/service_worker_context_wrapper.h"
16 #include "content/browser/service_worker/service_worker_registration.h"
17 #include "content/browser/service_worker/service_worker_test_utils.h"
18 #include "content/browser/service_worker/service_worker_version.h"
19 #include "content/common/service_worker/service_worker_messages.h"
20 #include "content/common/service_worker/service_worker_status_code.h"
21 #include "content/common/service_worker/service_worker_types.h"
22 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/storage_partition.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/common/content_switches.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/content_browser_test.h"
30 #include "content/public/test/content_browser_test_utils.h"
31 #include "content/shell/browser/shell.h"
32 #include "net/test/embedded_test_server/embedded_test_server.h"
33 #include "net/test/embedded_test_server/http_request.h"
34 #include "net/test/embedded_test_server/http_response.h"
35 #include "net/url_request/url_request_filter.h"
36 #include "net/url_request/url_request_interceptor.h"
37 #include "net/url_request/url_request_test_job.h"
38 #include "storage/browser/blob/blob_data_handle.h"
39 #include "storage/browser/blob/blob_storage_context.h"
40 #include "storage/common/blob/blob_data.h"
42 namespace content {
44 namespace {
46 struct FetchResult {
47 ServiceWorkerStatusCode status;
48 ServiceWorkerFetchEventResult result;
49 ServiceWorkerResponse response;
50 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
53 void RunAndQuit(const base::Closure& closure,
54 const base::Closure& quit,
55 base::MessageLoopProxy* original_message_loop) {
56 closure.Run();
57 original_message_loop->PostTask(FROM_HERE, quit);
60 void RunOnIOThread(const base::Closure& closure) {
61 base::RunLoop run_loop;
62 BrowserThread::PostTask(
63 BrowserThread::IO, FROM_HERE,
64 base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(),
65 base::MessageLoopProxy::current()));
66 run_loop.Run();
69 void RunOnIOThread(
70 const base::Callback<void(const base::Closure& continuation)>& closure) {
71 base::RunLoop run_loop;
72 base::Closure quit_on_original_thread =
73 base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
74 base::MessageLoopProxy::current().get(),
75 FROM_HERE,
76 run_loop.QuitClosure());
77 BrowserThread::PostTask(BrowserThread::IO,
78 FROM_HERE,
79 base::Bind(closure, quit_on_original_thread));
80 run_loop.Run();
83 void ReceivePrepareResult(bool* is_prepared) {
84 *is_prepared = true;
87 base::Closure CreatePrepareReceiver(bool* is_prepared) {
88 return base::Bind(&ReceivePrepareResult, is_prepared);
91 // Contrary to the style guide, the output parameter of this function comes
92 // before input parameters so Bind can be used on it to create a FetchCallback
93 // to pass to DispatchFetchEvent.
94 void ReceiveFetchResult(BrowserThread::ID run_quit_thread,
95 const base::Closure& quit,
96 ChromeBlobStorageContext* blob_context,
97 FetchResult* out_result,
98 ServiceWorkerStatusCode actual_status,
99 ServiceWorkerFetchEventResult actual_result,
100 const ServiceWorkerResponse& actual_response) {
101 out_result->status = actual_status;
102 out_result->result = actual_result;
103 out_result->response = actual_response;
104 if (!actual_response.blob_uuid.empty()) {
105 out_result->blob_data_handle =
106 blob_context->context()->GetBlobDataFromUUID(
107 actual_response.blob_uuid);
109 if (!quit.is_null())
110 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
113 ServiceWorkerVersion::FetchCallback CreateResponseReceiver(
114 BrowserThread::ID run_quit_thread,
115 const base::Closure& quit,
116 ChromeBlobStorageContext* blob_context,
117 FetchResult* result) {
118 return base::Bind(&ReceiveFetchResult, run_quit_thread, quit,
119 make_scoped_refptr<ChromeBlobStorageContext>(blob_context),
120 result);
123 void ReadResponseBody(std::string* body,
124 storage::BlobDataHandle* blob_data_handle) {
125 ASSERT_TRUE(blob_data_handle);
126 ASSERT_EQ(1U, blob_data_handle->data()->items().size());
127 *body = std::string(blob_data_handle->data()->items()[0].bytes(),
128 blob_data_handle->data()->items()[0].length());
131 void ExpectResultAndRun(bool expected,
132 const base::Closure& continuation,
133 bool actual) {
134 EXPECT_EQ(expected, actual);
135 continuation.Run();
138 class WorkerActivatedObserver
139 : public ServiceWorkerContextObserver,
140 public base::RefCountedThreadSafe<WorkerActivatedObserver> {
141 public:
142 explicit WorkerActivatedObserver(ServiceWorkerContextWrapper* context)
143 : context_(context) {}
144 void Init() {
145 RunOnIOThread(base::Bind(&WorkerActivatedObserver::InitOnIOThread, this));
147 // ServiceWorkerContextObserver overrides.
148 void OnVersionStateChanged(int64 version_id) override {
149 DCHECK_CURRENTLY_ON(BrowserThread::IO);
150 const ServiceWorkerVersion* version =
151 context_->context()->GetLiveVersion(version_id);
152 if (version->status() == ServiceWorkerVersion::ACTIVATED) {
153 context_->RemoveObserver(this);
154 BrowserThread::PostTask(BrowserThread::UI,
155 FROM_HERE,
156 base::Bind(&WorkerActivatedObserver::Quit, this));
159 void Wait() { run_loop_.Run(); }
161 private:
162 friend class base::RefCountedThreadSafe<WorkerActivatedObserver>;
163 ~WorkerActivatedObserver() override {}
164 void InitOnIOThread() { context_->AddObserver(this); }
165 void Quit() { run_loop_.Quit(); }
167 base::RunLoop run_loop_;
168 ServiceWorkerContextWrapper* context_;
169 DISALLOW_COPY_AND_ASSIGN(WorkerActivatedObserver);
172 scoped_ptr<net::test_server::HttpResponse> VerifyServiceWorkerHeaderInRequest(
173 const net::test_server::HttpRequest& request) {
174 EXPECT_EQ(request.relative_url, "/service_worker/generated_sw.js");
175 std::map<std::string, std::string>::const_iterator it =
176 request.headers.find("Service-Worker");
177 EXPECT_TRUE(it != request.headers.end());
178 EXPECT_EQ("script", it->second);
180 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
181 new net::test_server::BasicHttpResponse());
182 http_response->set_content_type("text/javascript");
183 return http_response.Pass();
186 // The ImportsBustMemcache test requires that the imported script
187 // would naturally be cached in blink's memcache, but the embedded
188 // test server doesn't produce headers that allow the blink's memcache
189 // to do that. This interceptor injects headers that give the import
190 // an experiration far in the future.
191 class LongLivedResourceInterceptor : public net::URLRequestInterceptor {
192 public:
193 LongLivedResourceInterceptor(const std::string& body)
194 : body_(body) {}
195 ~LongLivedResourceInterceptor() override {}
197 // net::URLRequestInterceptor implementation
198 net::URLRequestJob* MaybeInterceptRequest(
199 net::URLRequest* request,
200 net::NetworkDelegate* network_delegate) const override {
201 const char kHeaders[] =
202 "HTTP/1.1 200 OK\0"
203 "Content-Type: text/javascript\0"
204 "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
205 "\0";
206 std::string headers(kHeaders, arraysize(kHeaders));
207 return new net::URLRequestTestJob(
208 request, network_delegate, headers, body_, true);
211 private:
212 std::string body_;
213 DISALLOW_COPY_AND_ASSIGN(LongLivedResourceInterceptor);
216 void CreateLongLivedResourceInterceptors(
217 const GURL& worker_url, const GURL& import_url) {
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
219 scoped_ptr<net::URLRequestInterceptor> interceptor;
221 interceptor.reset(new LongLivedResourceInterceptor(
222 "importScripts('long_lived_import.js');"));
223 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
224 worker_url, interceptor.Pass());
226 interceptor.reset(new LongLivedResourceInterceptor(
227 "// the imported script does nothing"));
228 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
229 import_url, interceptor.Pass());
232 void CountScriptResources(
233 ServiceWorkerContextWrapper* wrapper,
234 const GURL& scope,
235 int* num_resources) {
236 *num_resources = -1;
238 std::vector<ServiceWorkerRegistrationInfo> infos =
239 wrapper->context()->GetAllLiveRegistrationInfo();
240 if (infos.empty())
241 return;
243 int version_id;
244 size_t index = infos.size() - 1;
245 if (infos[index].installing_version.version_id !=
246 kInvalidServiceWorkerVersionId)
247 version_id = infos[index].installing_version.version_id;
248 else if (infos[index].waiting_version.version_id !=
249 kInvalidServiceWorkerVersionId)
250 version_id = infos[1].waiting_version.version_id;
251 else if (infos[index].active_version.version_id !=
252 kInvalidServiceWorkerVersionId)
253 version_id = infos[index].active_version.version_id;
254 else
255 return;
257 ServiceWorkerVersion* version =
258 wrapper->context()->GetLiveVersion(version_id);
259 *num_resources = static_cast<int>(version->script_cache_map()->size());
262 } // namespace
264 class ServiceWorkerBrowserTest : public ContentBrowserTest {
265 protected:
266 typedef ServiceWorkerBrowserTest self;
268 void SetUpCommandLine(base::CommandLine* command_line) override {
269 command_line->AppendSwitch(
270 switches::kEnableExperimentalWebPlatformFeatures);
273 void SetUpOnMainThread() override {
274 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
275 StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
276 shell()->web_contents()->GetBrowserContext());
277 wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
278 partition->GetServiceWorkerContext());
280 // Navigate to the page to set up a renderer page (where we can embed
281 // a worker).
282 NavigateToURLBlockUntilNavigationsComplete(
283 shell(),
284 embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
286 RunOnIOThread(base::Bind(&self::SetUpOnIOThread, this));
289 void TearDownOnMainThread() override {
290 RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this));
291 wrapper_ = NULL;
294 virtual void SetUpOnIOThread() {}
295 virtual void TearDownOnIOThread() {}
297 ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
298 ServiceWorkerContext* public_context() { return wrapper(); }
300 void AssociateRendererProcessToPattern(const GURL& pattern) {
301 wrapper_->process_manager()->AddProcessReferenceToPattern(
302 pattern, shell()->web_contents()->GetRenderProcessHost()->GetID());
305 private:
306 scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
309 class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
310 public EmbeddedWorkerInstance::Listener {
311 public:
312 typedef EmbeddedWorkerBrowserTest self;
314 EmbeddedWorkerBrowserTest()
315 : last_worker_status_(EmbeddedWorkerInstance::STOPPED),
316 pause_mode_(DONT_PAUSE) {}
317 ~EmbeddedWorkerBrowserTest() override {}
319 void TearDownOnIOThread() override {
320 if (worker_) {
321 worker_->RemoveListener(this);
322 worker_.reset();
326 void StartOnIOThread() {
327 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
328 worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
329 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
330 worker_->AddListener(this);
333 const int64 service_worker_version_id = 33L;
334 const GURL pattern = embedded_test_server()->GetURL("/");
335 const GURL script_url = embedded_test_server()->GetURL(
336 "/service_worker/worker.js");
337 AssociateRendererProcessToPattern(pattern);
338 int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
339 wrapper()->process_manager()->AddProcessReferenceToPattern(
340 pattern, process_id);
341 worker_->Start(
342 service_worker_version_id,
343 pattern,
344 script_url,
345 pause_mode_ != DONT_PAUSE,
346 base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
348 void StartOnIOThread2(ServiceWorkerStatusCode status) {
349 last_worker_status_ = worker_->status();
350 EXPECT_EQ(SERVICE_WORKER_OK, status);
351 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
353 if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
354 done_closure_.Run();
357 void StopOnIOThread() {
358 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
359 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status());
361 ServiceWorkerStatusCode status = worker_->Stop();
363 last_worker_status_ = worker_->status();
364 EXPECT_EQ(SERVICE_WORKER_OK, status);
365 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_);
367 if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
368 done_closure_.Run();
371 protected:
372 // EmbeddedWorkerInstance::Observer overrides:
373 void OnStarted() override {
374 ASSERT_TRUE(worker_ != NULL);
375 ASSERT_FALSE(done_closure_.is_null());
376 last_worker_status_ = worker_->status();
377 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
379 void OnStopped() override {
380 ASSERT_TRUE(worker_ != NULL);
381 ASSERT_FALSE(done_closure_.is_null());
382 last_worker_status_ = worker_->status();
383 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
385 void OnPausedAfterDownload() override {
386 if (pause_mode_ == PAUSE_THEN_RESUME)
387 worker_->ResumeAfterDownload();
388 else if (pause_mode_ == PAUSE_THEN_STOP)
389 worker_->Stop();
390 else
391 ASSERT_TRUE(false);
393 void OnReportException(const base::string16& error_message,
394 int line_number,
395 int column_number,
396 const GURL& source_url) override {}
397 void OnReportConsoleMessage(int source_identifier,
398 int message_level,
399 const base::string16& message,
400 int line_number,
401 const GURL& source_url) override {}
402 bool OnMessageReceived(const IPC::Message& message) override { return false; }
404 scoped_ptr<EmbeddedWorkerInstance> worker_;
405 EmbeddedWorkerInstance::Status last_worker_status_;
407 enum {
408 DONT_PAUSE,
409 PAUSE_THEN_RESUME,
410 PAUSE_THEN_STOP,
411 } pause_mode_;
413 // Called by EmbeddedWorkerInstance::Observer overrides so that
414 // test code can wait for the worker status notifications.
415 base::Closure done_closure_;
418 class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
419 public:
420 typedef ServiceWorkerVersionBrowserTest self;
422 ~ServiceWorkerVersionBrowserTest() override {}
424 void TearDownOnIOThread() override {
425 registration_ = NULL;
426 version_ = NULL;
429 void InstallTestHelper(const std::string& worker_url,
430 ServiceWorkerStatusCode expected_status) {
431 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
432 worker_url));
434 // Dispatch install on a worker.
435 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
436 base::RunLoop install_run_loop;
437 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
438 base::Bind(&self::InstallOnIOThread, this,
439 install_run_loop.QuitClosure(),
440 &status));
441 install_run_loop.Run();
442 ASSERT_EQ(expected_status, status);
444 // Stop the worker.
445 status = SERVICE_WORKER_ERROR_FAILED;
446 base::RunLoop stop_run_loop;
447 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
448 base::Bind(&self::StopOnIOThread, this,
449 stop_run_loop.QuitClosure(),
450 &status));
451 stop_run_loop.Run();
452 ASSERT_EQ(SERVICE_WORKER_OK, status);
455 void ActivateTestHelper(
456 const std::string& worker_url,
457 ServiceWorkerStatusCode expected_status) {
458 RunOnIOThread(
459 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
460 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
461 base::RunLoop run_loop;
462 BrowserThread::PostTask(
463 BrowserThread::IO,
464 FROM_HERE,
465 base::Bind(
466 &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status));
467 run_loop.Run();
468 ASSERT_EQ(expected_status, status);
471 void FetchOnRegisteredWorker(
472 ServiceWorkerFetchEventResult* result,
473 ServiceWorkerResponse* response,
474 scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
475 blob_context_ = ChromeBlobStorageContext::GetFor(
476 shell()->web_contents()->GetBrowserContext());
477 bool prepare_result = false;
478 FetchResult fetch_result;
479 fetch_result.status = SERVICE_WORKER_ERROR_FAILED;
480 base::RunLoop fetch_run_loop;
481 BrowserThread::PostTask(BrowserThread::IO,
482 FROM_HERE,
483 base::Bind(&self::FetchOnIOThread,
484 this,
485 fetch_run_loop.QuitClosure(),
486 &prepare_result,
487 &fetch_result));
488 fetch_run_loop.Run();
489 ASSERT_TRUE(prepare_result);
490 *result = fetch_result.result;
491 *response = fetch_result.response;
492 *blob_data_handle = fetch_result.blob_data_handle.Pass();
493 ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status);
496 void FetchTestHelper(const std::string& worker_url,
497 ServiceWorkerFetchEventResult* result,
498 ServiceWorkerResponse* response,
499 scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
500 RunOnIOThread(
501 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
502 FetchOnRegisteredWorker(result, response, blob_data_handle);
505 void SetUpRegistrationOnIOThread(const std::string& worker_url) {
506 const GURL pattern = embedded_test_server()->GetURL("/");
507 registration_ = new ServiceWorkerRegistration(
508 pattern,
509 wrapper()->context()->storage()->NewRegistrationId(),
510 wrapper()->context()->AsWeakPtr());
511 version_ = new ServiceWorkerVersion(
512 registration_.get(),
513 embedded_test_server()->GetURL(worker_url),
514 wrapper()->context()->storage()->NewVersionId(),
515 wrapper()->context()->AsWeakPtr());
516 AssociateRendererProcessToPattern(pattern);
519 void StartOnIOThread(const base::Closure& done,
520 ServiceWorkerStatusCode* result) {
521 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
522 version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result));
525 void InstallOnIOThread(const base::Closure& done,
526 ServiceWorkerStatusCode* result) {
527 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
528 version_->SetStatus(ServiceWorkerVersion::INSTALLING);
529 version_->DispatchInstallEvent(
530 -1, CreateReceiver(BrowserThread::UI, done, result));
533 void ActivateOnIOThread(const base::Closure& done,
534 ServiceWorkerStatusCode* result) {
535 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
536 version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
537 version_->DispatchActivateEvent(
538 CreateReceiver(BrowserThread::UI, done, result));
541 void FetchOnIOThread(const base::Closure& done,
542 bool* prepare_result,
543 FetchResult* result) {
544 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
545 ServiceWorkerFetchRequest request(
546 embedded_test_server()->GetURL("/service_worker/empty.html"),
547 "GET",
548 ServiceWorkerHeaderMap(),
549 GURL(""),
550 false);
551 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
552 version_->DispatchFetchEvent(
553 request,
554 CreatePrepareReceiver(prepare_result),
555 CreateResponseReceiver(
556 BrowserThread::UI, done, blob_context_.get(), result));
559 void StopOnIOThread(const base::Closure& done,
560 ServiceWorkerStatusCode* result) {
561 ASSERT_TRUE(version_.get());
562 version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
565 void SyncEventOnIOThread(const base::Closure& done,
566 ServiceWorkerStatusCode* result) {
567 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
568 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
569 version_->DispatchSyncEvent(
570 CreateReceiver(BrowserThread::UI, done, result));
573 protected:
574 scoped_refptr<ServiceWorkerRegistration> registration_;
575 scoped_refptr<ServiceWorkerVersion> version_;
576 scoped_refptr<ChromeBlobStorageContext> blob_context_;
579 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
580 // Start a worker and wait until OnStarted() is called.
581 base::RunLoop start_run_loop;
582 done_closure_ = start_run_loop.QuitClosure();
583 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
584 base::Bind(&self::StartOnIOThread, this));
585 start_run_loop.Run();
587 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
589 // Stop a worker and wait until OnStopped() is called.
590 base::RunLoop stop_run_loop;
591 done_closure_ = stop_run_loop.QuitClosure();
592 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
593 base::Bind(&self::StopOnIOThread, this));
594 stop_run_loop.Run();
596 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
599 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartPaused_ThenResume) {
600 pause_mode_ = PAUSE_THEN_RESUME;
601 base::RunLoop start_run_loop;
602 done_closure_ = start_run_loop.QuitClosure();
603 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
604 base::Bind(&self::StartOnIOThread, this));
605 start_run_loop.Run();
606 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
609 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
610 StartPaused_ThenStop) {
611 pause_mode_ = PAUSE_THEN_STOP;
612 base::RunLoop start_run_loop;
613 done_closure_ = start_run_loop.QuitClosure();
614 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
615 base::Bind(&self::StartOnIOThread, this));
616 start_run_loop.Run();
617 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
620 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
621 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
622 "/service_worker/worker.js"));
624 // Start a worker.
625 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
626 base::RunLoop start_run_loop;
627 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
628 base::Bind(&self::StartOnIOThread, this,
629 start_run_loop.QuitClosure(),
630 &status));
631 start_run_loop.Run();
632 ASSERT_EQ(SERVICE_WORKER_OK, status);
634 // Stop the worker.
635 status = SERVICE_WORKER_ERROR_FAILED;
636 base::RunLoop stop_run_loop;
637 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
638 base::Bind(&self::StopOnIOThread, this,
639 stop_run_loop.QuitClosure(),
640 &status));
641 stop_run_loop.Run();
642 ASSERT_EQ(SERVICE_WORKER_OK, status);
645 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
646 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
647 "/service_worker/nonexistent.js"));
649 // Start a worker for nonexistent URL.
650 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
651 base::RunLoop start_run_loop;
652 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
653 base::Bind(&self::StartOnIOThread, this,
654 start_run_loop.QuitClosure(),
655 &status));
656 start_run_loop.Run();
657 ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
660 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
661 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
664 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
665 InstallWithWaitUntil_Fulfilled) {
666 InstallTestHelper("/service_worker/worker_install_fulfilled.js",
667 SERVICE_WORKER_OK);
670 // Check that ServiceWorker script requests set a "Service-Worker: script"
671 // header.
672 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
673 ServiceWorkerScriptHeader) {
674 embedded_test_server()->RegisterRequestHandler(
675 base::Bind(&VerifyServiceWorkerHeaderInRequest));
676 InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
679 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
680 Activate_NoEventListener) {
681 ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
682 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
685 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
686 ActivateTestHelper("/service_worker/worker_activate_rejected.js",
687 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
690 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
691 InstallWithWaitUntil_Rejected) {
692 InstallTestHelper("/service_worker/worker_install_rejected.js",
693 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
696 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
697 ServiceWorkerFetchEventResult result;
698 ServiceWorkerResponse response;
699 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
700 FetchTestHelper("/service_worker/fetch_event.js",
701 &result, &response, &blob_data_handle);
702 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
703 EXPECT_EQ(301, response.status_code);
704 EXPECT_EQ("Moved Permanently", response.status_text);
705 ServiceWorkerHeaderMap expected_headers;
706 expected_headers["content-language"] = "fi";
707 expected_headers["content-type"] = "text/html; charset=UTF-8";
708 EXPECT_EQ(expected_headers, response.headers);
710 std::string body;
711 RunOnIOThread(
712 base::Bind(&ReadResponseBody,
713 &body, base::Owned(blob_data_handle.release())));
714 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body);
717 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
718 SyncAbortedWithoutFlag) {
719 RunOnIOThread(base::Bind(
720 &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
722 // Run the sync event.
723 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
724 base::RunLoop sync_run_loop;
725 BrowserThread::PostTask(BrowserThread::IO,
726 FROM_HERE,
727 base::Bind(&self::SyncEventOnIOThread,
728 this,
729 sync_run_loop.QuitClosure(),
730 &status));
731 sync_run_loop.Run();
732 ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
735 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
736 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
737 command_line->AppendSwitch(switches::kEnableServiceWorkerSync);
739 RunOnIOThread(base::Bind(
740 &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
741 ServiceWorkerFetchEventResult result;
742 ServiceWorkerResponse response;
743 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
744 // Should 404 before sync event.
745 FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
746 EXPECT_EQ(404, response.status_code);
748 // Run the sync event.
749 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
750 base::RunLoop sync_run_loop;
751 BrowserThread::PostTask(BrowserThread::IO,
752 FROM_HERE,
753 base::Bind(&self::SyncEventOnIOThread,
754 this,
755 sync_run_loop.QuitClosure(),
756 &status));
757 sync_run_loop.Run();
758 ASSERT_EQ(SERVICE_WORKER_OK, status);
760 // Should 200 after sync event.
761 FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
762 EXPECT_EQ(200, response.status_code);
765 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, Reload) {
766 const std::string kPageUrl = "/service_worker/reload.html";
767 const std::string kWorkerUrl = "/service_worker/fetch_event_reload.js";
769 scoped_refptr<WorkerActivatedObserver> observer =
770 new WorkerActivatedObserver(wrapper());
771 observer->Init();
772 public_context()->RegisterServiceWorker(
773 embedded_test_server()->GetURL(kPageUrl),
774 embedded_test_server()->GetURL(kWorkerUrl),
775 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
776 observer->Wait();
779 const base::string16 title = base::ASCIIToUTF16("reload=false");
780 TitleWatcher title_watcher(shell()->web_contents(), title);
781 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
782 EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
785 const base::string16 title = base::ASCIIToUTF16("reload=true");
786 TitleWatcher title_watcher(shell()->web_contents(), title);
787 ReloadBlockUntilNavigationsComplete(shell(), 1);
788 EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
790 shell()->Close();
792 base::RunLoop run_loop;
793 public_context()->UnregisterServiceWorker(
794 embedded_test_server()->GetURL(kPageUrl),
795 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
796 run_loop.Run();
800 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
801 const std::string kScopeUrl = "/service_worker/imports_bust_memcache_scope/";
802 const std::string kPageUrl = "/service_worker/imports_bust_memcache.html";
803 const std::string kScriptUrl = "/service_worker/worker_with_one_import.js";
804 const std::string kImportUrl = "/service_worker/long_lived_import.js";
805 const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
806 const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
808 RunOnIOThread(
809 base::Bind(&CreateLongLivedResourceInterceptors,
810 embedded_test_server()->GetURL(kScriptUrl),
811 embedded_test_server()->GetURL(kImportUrl)));
813 TitleWatcher title_watcher(shell()->web_contents(), kOKTitle);
814 title_watcher.AlsoWaitForTitle(kFailTitle);
815 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
816 base::string16 title = title_watcher.WaitAndGetTitle();
817 EXPECT_EQ(kOKTitle, title);
819 // Verify the number of resources in the implicit script cache is correct.
820 const int kExpectedNumResources = 2;
821 int num_resources = 0;
822 RunOnIOThread(
823 base::Bind(&CountScriptResources,
824 base::Unretained(wrapper()),
825 embedded_test_server()->GetURL(kScopeUrl),
826 &num_resources));
827 EXPECT_EQ(kExpectedNumResources, num_resources);
830 class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
831 public:
832 typedef ServiceWorkerBlackBoxBrowserTest self;
834 void FindRegistrationOnIO(const GURL& document_url,
835 ServiceWorkerStatusCode* status,
836 const base::Closure& continuation) {
837 wrapper()->context()->storage()->FindRegistrationForDocument(
838 document_url,
839 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
840 this,
841 status,
842 continuation));
845 void FindRegistrationOnIO2(
846 ServiceWorkerStatusCode* out_status,
847 const base::Closure& continuation,
848 ServiceWorkerStatusCode status,
849 const scoped_refptr<ServiceWorkerRegistration>& registration) {
850 *out_status = status;
851 if (!registration.get())
852 EXPECT_NE(SERVICE_WORKER_OK, status);
853 continuation.Run();
857 static int CountRenderProcessHosts() {
858 int result = 0;
859 for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
860 !iter.IsAtEnd();
861 iter.Advance()) {
862 result++;
864 return result;
867 // Flaky timeouts on CrOS: http://crbug.com/387045
868 #if defined(OS_CHROMEOS)
869 #define MAYBE_Registration DISABLED_Registration
870 #else
871 #define MAYBE_Registration Registration
872 #endif
873 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
874 // Close the only window to be sure we're not re-using its RenderProcessHost.
875 shell()->Close();
876 EXPECT_EQ(0, CountRenderProcessHosts());
878 const std::string kWorkerUrl = "/service_worker/fetch_event.js";
880 // Unregistering nothing should return false.
882 base::RunLoop run_loop;
883 public_context()->UnregisterServiceWorker(
884 embedded_test_server()->GetURL("/"),
885 base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
886 run_loop.Run();
889 // If we use a worker URL that doesn't exist, registration fails.
891 base::RunLoop run_loop;
892 public_context()->RegisterServiceWorker(
893 embedded_test_server()->GetURL("/"),
894 embedded_test_server()->GetURL("/does/not/exist"),
895 base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
896 run_loop.Run();
898 EXPECT_EQ(0, CountRenderProcessHosts());
900 // Register returns when the promise would be resolved.
902 base::RunLoop run_loop;
903 public_context()->RegisterServiceWorker(
904 embedded_test_server()->GetURL("/"),
905 embedded_test_server()->GetURL(kWorkerUrl),
906 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
907 run_loop.Run();
909 EXPECT_EQ(1, CountRenderProcessHosts());
911 // Registering again should succeed, although the algo still
912 // might not be complete.
914 base::RunLoop run_loop;
915 public_context()->RegisterServiceWorker(
916 embedded_test_server()->GetURL("/"),
917 embedded_test_server()->GetURL(kWorkerUrl),
918 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
919 run_loop.Run();
922 // The registration algo might not be far enough along to have
923 // stored the registration data, so it may not be findable
924 // at this point.
926 // Unregistering something should return true.
928 base::RunLoop run_loop;
929 public_context()->UnregisterServiceWorker(
930 embedded_test_server()->GetURL("/"),
931 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
932 run_loop.Run();
934 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
935 "workers eagerly, so their RPHs "
936 "can still be running.";
938 // Should not be able to find it.
940 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
941 RunOnIOThread(
942 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
943 this,
944 embedded_test_server()->GetURL("/service_worker/empty.html"),
945 &status));
946 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
950 } // namespace content