Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_browsertest.cc
bloba1a26585aa8ce99a5889f486888716fdaddede49
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 "webkit/browser/blob/blob_data_handle.h"
39 #include "webkit/browser/blob/blob_storage_context.h"
40 #include "webkit/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 virtual 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 virtual ~WorkerActivatedObserver() {}
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.PassAs<net::test_server::HttpResponse>();
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 virtual ~LongLivedResourceInterceptor() {}
197 // net::URLRequestInterceptor implementation
198 virtual 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.is_null)
246 version_id = infos[index].installing_version.version_id;
247 else if (!infos[index].waiting_version.is_null)
248 version_id = infos[1].waiting_version.version_id;
249 else if (!infos[index].active_version.is_null)
250 version_id = infos[index].active_version.version_id;
251 else
252 return;
254 ServiceWorkerVersion* version =
255 wrapper->context()->GetLiveVersion(version_id);
256 *num_resources = static_cast<int>(version->script_cache_map()->size());
259 } // namespace
261 class ServiceWorkerBrowserTest : public ContentBrowserTest {
262 protected:
263 typedef ServiceWorkerBrowserTest self;
265 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
266 command_line->AppendSwitch(
267 switches::kEnableExperimentalWebPlatformFeatures);
270 virtual void SetUpOnMainThread() OVERRIDE {
271 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
272 StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
273 shell()->web_contents()->GetBrowserContext());
274 wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
275 partition->GetServiceWorkerContext());
277 // Navigate to the page to set up a renderer page (where we can embed
278 // a worker).
279 NavigateToURLBlockUntilNavigationsComplete(
280 shell(),
281 embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
283 RunOnIOThread(base::Bind(&self::SetUpOnIOThread, this));
286 virtual void TearDownOnMainThread() OVERRIDE {
287 RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this));
288 wrapper_ = NULL;
291 virtual void SetUpOnIOThread() {}
292 virtual void TearDownOnIOThread() {}
294 ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
295 ServiceWorkerContext* public_context() { return wrapper(); }
297 void AssociateRendererProcessToWorker(EmbeddedWorkerInstance* worker) {
298 worker->AddProcessReference(
299 shell()->web_contents()->GetRenderProcessHost()->GetID());
302 private:
303 scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
306 class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
307 public EmbeddedWorkerInstance::Listener {
308 public:
309 typedef EmbeddedWorkerBrowserTest self;
311 EmbeddedWorkerBrowserTest()
312 : last_worker_status_(EmbeddedWorkerInstance::STOPPED),
313 pause_mode_(DONT_PAUSE) {}
314 virtual ~EmbeddedWorkerBrowserTest() {}
316 virtual void TearDownOnIOThread() OVERRIDE {
317 if (worker_) {
318 worker_->RemoveListener(this);
319 worker_.reset();
323 void StartOnIOThread() {
324 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
325 worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
326 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
327 worker_->AddListener(this);
329 AssociateRendererProcessToWorker(worker_.get());
331 const int64 service_worker_version_id = 33L;
332 const GURL scope = embedded_test_server()->GetURL("/");
333 const GURL script_url = embedded_test_server()->GetURL(
334 "/service_worker/worker.js");
335 std::vector<int> processes;
336 processes.push_back(
337 shell()->web_contents()->GetRenderProcessHost()->GetID());
338 worker_->Start(
339 service_worker_version_id,
340 scope,
341 script_url,
342 pause_mode_ != DONT_PAUSE,
343 processes,
344 base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
346 void StartOnIOThread2(ServiceWorkerStatusCode status) {
347 last_worker_status_ = worker_->status();
348 EXPECT_EQ(SERVICE_WORKER_OK, status);
349 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
351 if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
352 done_closure_.Run();
355 void StopOnIOThread() {
356 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
357 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status());
359 ServiceWorkerStatusCode status = worker_->Stop();
361 last_worker_status_ = worker_->status();
362 EXPECT_EQ(SERVICE_WORKER_OK, status);
363 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_);
365 if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
366 done_closure_.Run();
369 protected:
370 // EmbeddedWorkerInstance::Observer overrides:
371 virtual void OnStarted() OVERRIDE {
372 ASSERT_TRUE(worker_ != NULL);
373 ASSERT_FALSE(done_closure_.is_null());
374 last_worker_status_ = worker_->status();
375 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
377 virtual void OnStopped() OVERRIDE {
378 ASSERT_TRUE(worker_ != NULL);
379 ASSERT_FALSE(done_closure_.is_null());
380 last_worker_status_ = worker_->status();
381 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
383 virtual void OnPausedAfterDownload() OVERRIDE {
384 if (pause_mode_ == PAUSE_THEN_RESUME)
385 worker_->ResumeAfterDownload();
386 else if (pause_mode_ == PAUSE_THEN_STOP)
387 worker_->Stop();
388 else
389 ASSERT_TRUE(false);
391 virtual void OnReportException(const base::string16& error_message,
392 int line_number,
393 int column_number,
394 const GURL& source_url) OVERRIDE {}
395 virtual void OnReportConsoleMessage(int source_identifier,
396 int message_level,
397 const base::string16& message,
398 int line_number,
399 const GURL& source_url) OVERRIDE {}
400 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
401 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 virtual ~ServiceWorkerVersionBrowserTest() {}
424 virtual 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 registration_ = new ServiceWorkerRegistration(
507 embedded_test_server()->GetURL("/"),
508 wrapper()->context()->storage()->NewRegistrationId(),
509 wrapper()->context()->AsWeakPtr());
510 version_ = new ServiceWorkerVersion(
511 registration_.get(),
512 embedded_test_server()->GetURL(worker_url),
513 wrapper()->context()->storage()->NewVersionId(),
514 wrapper()->context()->AsWeakPtr());
515 AssociateRendererProcessToWorker(version_->embedded_worker());
518 void StartOnIOThread(const base::Closure& done,
519 ServiceWorkerStatusCode* result) {
520 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
521 version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result));
524 void InstallOnIOThread(const base::Closure& done,
525 ServiceWorkerStatusCode* result) {
526 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
527 version_->SetStatus(ServiceWorkerVersion::INSTALLING);
528 version_->DispatchInstallEvent(
529 -1, CreateReceiver(BrowserThread::UI, done, result));
532 void ActivateOnIOThread(const base::Closure& done,
533 ServiceWorkerStatusCode* result) {
534 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
535 version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
536 version_->DispatchActivateEvent(
537 CreateReceiver(BrowserThread::UI, done, result));
540 void FetchOnIOThread(const base::Closure& done,
541 bool* prepare_result,
542 FetchResult* result) {
543 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
544 ServiceWorkerFetchRequest request(
545 embedded_test_server()->GetURL("/service_worker/empty.html"),
546 "GET",
547 std::map<std::string, std::string>(),
548 GURL(""),
549 false);
550 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
551 version_->DispatchFetchEvent(
552 request,
553 CreatePrepareReceiver(prepare_result),
554 CreateResponseReceiver(
555 BrowserThread::UI, done, blob_context_.get(), result));
558 void StopOnIOThread(const base::Closure& done,
559 ServiceWorkerStatusCode* result) {
560 ASSERT_TRUE(version_.get());
561 version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
564 void SyncEventOnIOThread(const base::Closure& done,
565 ServiceWorkerStatusCode* result) {
566 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
567 version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
568 version_->DispatchSyncEvent(
569 CreateReceiver(BrowserThread::UI, done, result));
572 protected:
573 scoped_refptr<ServiceWorkerRegistration> registration_;
574 scoped_refptr<ServiceWorkerVersion> version_;
575 scoped_refptr<ChromeBlobStorageContext> blob_context_;
578 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
579 // Start a worker and wait until OnStarted() is called.
580 base::RunLoop start_run_loop;
581 done_closure_ = start_run_loop.QuitClosure();
582 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
583 base::Bind(&self::StartOnIOThread, this));
584 start_run_loop.Run();
586 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
588 // Stop a worker and wait until OnStopped() is called.
589 base::RunLoop stop_run_loop;
590 done_closure_ = stop_run_loop.QuitClosure();
591 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
592 base::Bind(&self::StopOnIOThread, this));
593 stop_run_loop.Run();
595 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
598 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartPaused_ThenResume) {
599 pause_mode_ = PAUSE_THEN_RESUME;
600 base::RunLoop start_run_loop;
601 done_closure_ = start_run_loop.QuitClosure();
602 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
603 base::Bind(&self::StartOnIOThread, this));
604 start_run_loop.Run();
605 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
608 IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
609 StartPaused_ThenStop) {
610 pause_mode_ = PAUSE_THEN_STOP;
611 base::RunLoop start_run_loop;
612 done_closure_ = start_run_loop.QuitClosure();
613 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
614 base::Bind(&self::StartOnIOThread, this));
615 start_run_loop.Run();
616 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
619 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
620 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
621 "/service_worker/worker.js"));
623 // Start a worker.
624 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
625 base::RunLoop start_run_loop;
626 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
627 base::Bind(&self::StartOnIOThread, this,
628 start_run_loop.QuitClosure(),
629 &status));
630 start_run_loop.Run();
631 ASSERT_EQ(SERVICE_WORKER_OK, status);
633 // Stop the worker.
634 status = SERVICE_WORKER_ERROR_FAILED;
635 base::RunLoop stop_run_loop;
636 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
637 base::Bind(&self::StopOnIOThread, this,
638 stop_run_loop.QuitClosure(),
639 &status));
640 stop_run_loop.Run();
641 ASSERT_EQ(SERVICE_WORKER_OK, status);
644 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
645 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
646 "/service_worker/nonexistent.js"));
648 // Start a worker for nonexistent URL.
649 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
650 base::RunLoop start_run_loop;
651 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
652 base::Bind(&self::StartOnIOThread, this,
653 start_run_loop.QuitClosure(),
654 &status));
655 start_run_loop.Run();
656 ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
659 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
660 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
663 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
664 InstallWithWaitUntil_Fulfilled) {
665 InstallTestHelper("/service_worker/worker_install_fulfilled.js",
666 SERVICE_WORKER_OK);
669 // Check that ServiceWorker script requests set a "Service-Worker: script"
670 // header.
671 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
672 ServiceWorkerScriptHeader) {
673 embedded_test_server()->RegisterRequestHandler(
674 base::Bind(&VerifyServiceWorkerHeaderInRequest));
675 InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
678 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
679 Activate_NoEventListener) {
680 ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
681 ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
684 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
685 ActivateTestHelper("/service_worker/worker_activate_rejected.js",
686 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
689 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
690 InstallWithWaitUntil_Rejected) {
691 InstallTestHelper("/service_worker/worker_install_rejected.js",
692 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
695 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
696 ServiceWorkerFetchEventResult result;
697 ServiceWorkerResponse response;
698 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
699 FetchTestHelper("/service_worker/fetch_event.js",
700 &result, &response, &blob_data_handle);
701 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
702 EXPECT_EQ(301, response.status_code);
703 EXPECT_EQ("Moved Permanently", response.status_text);
704 std::map<std::string, std::string> expected_headers;
705 expected_headers["content-language"] = "fi";
706 expected_headers["content-type"] = "text/html; charset=UTF-8";
707 EXPECT_EQ(expected_headers, response.headers);
709 std::string body;
710 RunOnIOThread(
711 base::Bind(&ReadResponseBody,
712 &body, base::Owned(blob_data_handle.release())));
713 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body);
716 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
717 SyncAbortedWithoutFlag) {
718 RunOnIOThread(base::Bind(
719 &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
721 // Run the sync event.
722 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
723 base::RunLoop sync_run_loop;
724 BrowserThread::PostTask(BrowserThread::IO,
725 FROM_HERE,
726 base::Bind(&self::SyncEventOnIOThread,
727 this,
728 sync_run_loop.QuitClosure(),
729 &status));
730 sync_run_loop.Run();
731 ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
734 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
735 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
736 command_line->AppendSwitch(switches::kEnableServiceWorkerSync);
738 RunOnIOThread(base::Bind(
739 &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
740 ServiceWorkerFetchEventResult result;
741 ServiceWorkerResponse response;
742 scoped_ptr<storage::BlobDataHandle> blob_data_handle;
743 // Should 404 before sync event.
744 FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
745 EXPECT_EQ(404, response.status_code);
747 // Run the sync event.
748 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
749 base::RunLoop sync_run_loop;
750 BrowserThread::PostTask(BrowserThread::IO,
751 FROM_HERE,
752 base::Bind(&self::SyncEventOnIOThread,
753 this,
754 sync_run_loop.QuitClosure(),
755 &status));
756 sync_run_loop.Run();
757 ASSERT_EQ(SERVICE_WORKER_OK, status);
759 // Should 200 after sync event.
760 FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
761 EXPECT_EQ(200, response.status_code);
764 // ServiceWorkerBrowserTest.Reload is flaky on Android crbug.com/393486
765 #if defined(OS_ANDROID)
766 #define MAYBE_Reload DISABLED_Reload
767 #else
768 #define MAYBE_Reload Reload
769 #endif
770 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, MAYBE_Reload) {
771 const std::string kPageUrl = "/service_worker/reload.html";
772 const std::string kWorkerUrl = "/service_worker/fetch_event_reload.js";
774 scoped_refptr<WorkerActivatedObserver> observer =
775 new WorkerActivatedObserver(wrapper());
776 observer->Init();
777 public_context()->RegisterServiceWorker(
778 embedded_test_server()->GetURL(kPageUrl),
779 embedded_test_server()->GetURL(kWorkerUrl),
780 base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
781 observer->Wait();
784 const base::string16 title = base::ASCIIToUTF16("reload=false");
785 TitleWatcher title_watcher(shell()->web_contents(), title);
786 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
787 EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
790 const base::string16 title = base::ASCIIToUTF16("reload=true");
791 TitleWatcher title_watcher(shell()->web_contents(), title);
792 ReloadBlockUntilNavigationsComplete(shell(), 1);
793 EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
795 shell()->Close();
797 base::RunLoop run_loop;
798 public_context()->UnregisterServiceWorker(
799 embedded_test_server()->GetURL(kPageUrl),
800 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
801 run_loop.Run();
805 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
806 const std::string kScopeUrl = "/service_worker/imports_bust_memcache_scope/";
807 const std::string kPageUrl = "/service_worker/imports_bust_memcache.html";
808 const std::string kScriptUrl = "/service_worker/worker_with_one_import.js";
809 const std::string kImportUrl = "/service_worker/long_lived_import.js";
810 const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
811 const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
813 RunOnIOThread(
814 base::Bind(&CreateLongLivedResourceInterceptors,
815 embedded_test_server()->GetURL(kScriptUrl),
816 embedded_test_server()->GetURL(kImportUrl)));
818 TitleWatcher title_watcher(shell()->web_contents(), kOKTitle);
819 title_watcher.AlsoWaitForTitle(kFailTitle);
820 NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
821 base::string16 title = title_watcher.WaitAndGetTitle();
822 EXPECT_EQ(kOKTitle, title);
824 // Verify the number of resources in the implicit script cache is correct.
825 const int kExpectedNumResources = 2;
826 int num_resources = 0;
827 RunOnIOThread(
828 base::Bind(&CountScriptResources,
829 base::Unretained(wrapper()),
830 embedded_test_server()->GetURL(kScopeUrl),
831 &num_resources));
832 EXPECT_EQ(kExpectedNumResources, num_resources);
835 class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
836 public:
837 typedef ServiceWorkerBlackBoxBrowserTest self;
839 void FindRegistrationOnIO(const GURL& document_url,
840 ServiceWorkerStatusCode* status,
841 const base::Closure& continuation) {
842 wrapper()->context()->storage()->FindRegistrationForDocument(
843 document_url,
844 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
845 this,
846 status,
847 continuation));
850 void FindRegistrationOnIO2(
851 ServiceWorkerStatusCode* out_status,
852 const base::Closure& continuation,
853 ServiceWorkerStatusCode status,
854 const scoped_refptr<ServiceWorkerRegistration>& registration) {
855 *out_status = status;
856 if (!registration.get())
857 EXPECT_NE(SERVICE_WORKER_OK, status);
858 continuation.Run();
862 static int CountRenderProcessHosts() {
863 int result = 0;
864 for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
865 !iter.IsAtEnd();
866 iter.Advance()) {
867 result++;
869 return result;
872 // Crashes on Android and flakes on CrOS: http://crbug.com/387045
873 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
874 #define MAYBE_Registration DISABLED_Registration
875 #else
876 #define MAYBE_Registration Registration
877 #endif
878 IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
879 // Close the only window to be sure we're not re-using its RenderProcessHost.
880 shell()->Close();
881 EXPECT_EQ(0, CountRenderProcessHosts());
883 const std::string kWorkerUrl = "/service_worker/fetch_event.js";
885 // Unregistering nothing should return true.
887 base::RunLoop run_loop;
888 public_context()->UnregisterServiceWorker(
889 embedded_test_server()->GetURL("/"),
890 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
891 run_loop.Run();
894 // If we use a worker URL that doesn't exist, registration fails.
896 base::RunLoop run_loop;
897 public_context()->RegisterServiceWorker(
898 embedded_test_server()->GetURL("/"),
899 embedded_test_server()->GetURL("/does/not/exist"),
900 base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
901 run_loop.Run();
903 EXPECT_EQ(0, CountRenderProcessHosts());
905 // Register returns when the promise would be resolved.
907 base::RunLoop run_loop;
908 public_context()->RegisterServiceWorker(
909 embedded_test_server()->GetURL("/"),
910 embedded_test_server()->GetURL(kWorkerUrl),
911 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
912 run_loop.Run();
914 EXPECT_EQ(1, CountRenderProcessHosts());
916 // Registering again should succeed, although the algo still
917 // might not be complete.
919 base::RunLoop run_loop;
920 public_context()->RegisterServiceWorker(
921 embedded_test_server()->GetURL("/"),
922 embedded_test_server()->GetURL(kWorkerUrl),
923 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
924 run_loop.Run();
927 // The registration algo might not be far enough along to have
928 // stored the registration data, so it may not be findable
929 // at this point.
931 // Unregistering something should return true.
933 base::RunLoop run_loop;
934 public_context()->UnregisterServiceWorker(
935 embedded_test_server()->GetURL("/"),
936 base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
937 run_loop.Run();
939 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
940 "workers eagerly, so their RPHs "
941 "can still be running.";
943 // Should not be able to find it.
945 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
946 RunOnIOThread(
947 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
948 this,
949 embedded_test_server()->GetURL("/service_worker/empty.html"),
950 &status));
951 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
955 } // namespace content