service_worker_browsertest.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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. 4 5#include "base/bind.h" 6#include "base/callback.h" 7#include "base/command_line.h" 8#include "base/run_loop.h" 9#include "content/browser/fileapi/chrome_blob_storage_context.h" 10#include "content/browser/service_worker/embedded_worker_instance.h" 11#include "content/browser/service_worker/embedded_worker_registry.h" 12#include "content/browser/service_worker/service_worker_context_core.h" 13#include "content/browser/service_worker/service_worker_context_wrapper.h" 14#include "content/browser/service_worker/service_worker_registration.h" 15#include "content/browser/service_worker/service_worker_test_utils.h" 16#include "content/browser/service_worker/service_worker_version.h" 17#include "content/common/service_worker/service_worker_messages.h" 18#include "content/common/service_worker/service_worker_status_code.h" 19#include "content/common/service_worker/service_worker_types.h" 20#include "content/public/browser/browser_context.h" 21#include "content/public/browser/browser_thread.h" 22#include "content/public/browser/render_process_host.h" 23#include "content/public/browser/storage_partition.h" 24#include "content/public/browser/web_contents.h" 25#include "content/public/common/content_switches.h" 26#include "content/public/test/content_browser_test.h" 27#include "content/public/test/content_browser_test_utils.h" 28#include "content/shell/browser/shell.h" 29#include "net/test/embedded_test_server/embedded_test_server.h" 30#include "webkit/browser/blob/blob_data_handle.h" 31#include "webkit/browser/blob/blob_storage_context.h" 32#include "webkit/common/blob/blob_data.h" 33 34namespace content { 35 36namespace { 37 38struct FetchResult { 39 ServiceWorkerStatusCode status; 40 ServiceWorkerFetchEventResult result; 41 ServiceWorkerResponse response; 42}; 43 44void RunAndQuit(const base::Closure& closure, 45 const base::Closure& quit, 46 base::MessageLoopProxy* original_message_loop) { 47 closure.Run(); 48 original_message_loop->PostTask(FROM_HERE, quit); 49} 50 51void RunOnIOThread(const base::Closure& closure) { 52 base::RunLoop run_loop; 53 BrowserThread::PostTask( 54 BrowserThread::IO, FROM_HERE, 55 base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(), 56 base::MessageLoopProxy::current())); 57 run_loop.Run(); 58} 59 60void RunOnIOThread( 61 const base::Callback<void(const base::Closure& continuation)>& closure) { 62 base::RunLoop run_loop; 63 base::Closure quit_on_original_thread = 64 base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask), 65 base::MessageLoopProxy::current().get(), 66 FROM_HERE, 67 run_loop.QuitClosure()); 68 BrowserThread::PostTask(BrowserThread::IO, 69 FROM_HERE, 70 base::Bind(closure, quit_on_original_thread)); 71 run_loop.Run(); 72} 73 74// Contrary to the style guide, the output parameter of this function comes 75// before input parameters so Bind can be used on it to create a FetchCallback 76// to pass to DispatchFetchEvent. 77void ReceiveFetchResult(BrowserThread::ID run_quit_thread, 78 const base::Closure& quit, 79 FetchResult* out_result, 80 ServiceWorkerStatusCode actual_status, 81 ServiceWorkerFetchEventResult actual_result, 82 const ServiceWorkerResponse& actual_response) { 83 out_result->status = actual_status; 84 out_result->result = actual_result; 85 out_result->response = actual_response; 86 if (!quit.is_null()) 87 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit); 88} 89 90ServiceWorkerVersion::FetchCallback CreateResponseReceiver( 91 BrowserThread::ID run_quit_thread, 92 const base::Closure& quit, 93 FetchResult* result) { 94 return base::Bind(&ReceiveFetchResult, run_quit_thread, quit, result); 95} 96 97void ReadResponseBody(std::string* body, 98 scoped_refptr<ChromeBlobStorageContext> context, 99 std::string blob_uuid) { 100 scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle = 101 context->context()->GetBlobDataFromUUID(blob_uuid); 102 ASSERT_EQ(1U, blob_data_handle->data()->items().size()); 103 *body = std::string(blob_data_handle->data()->items()[0].bytes(), 104 blob_data_handle->data()->items()[0].length()); 105} 106 107} // namespace 108 109class ServiceWorkerBrowserTest : public ContentBrowserTest { 110 protected: 111 typedef ServiceWorkerBrowserTest self; 112 113 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 114 command_line->AppendSwitch(switches::kEnableServiceWorker); 115 } 116 117 virtual void SetUpOnMainThread() OVERRIDE { 118 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 119 StoragePartition* partition = BrowserContext::GetDefaultStoragePartition( 120 shell()->web_contents()->GetBrowserContext()); 121 wrapper_ = static_cast<ServiceWorkerContextWrapper*>( 122 partition->GetServiceWorkerContext()); 123 124 // Navigate to the page to set up a renderer page (where we can embed 125 // a worker). 126 NavigateToURLBlockUntilNavigationsComplete( 127 shell(), 128 embedded_test_server()->GetURL("/service_worker/empty.html"), 1); 129 130 RunOnIOThread(base::Bind(&self::SetUpOnIOThread, this)); 131 } 132 133 virtual void TearDownOnMainThread() OVERRIDE { 134 RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this)); 135 wrapper_ = NULL; 136 } 137 138 virtual void SetUpOnIOThread() {} 139 virtual void TearDownOnIOThread() {} 140 141 ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); } 142 ServiceWorkerContext* public_context() { return wrapper(); } 143 144 void AssociateRendererProcessToWorker(EmbeddedWorkerInstance* worker) { 145 worker->AddProcessReference( 146 shell()->web_contents()->GetRenderProcessHost()->GetID()); 147 } 148 149 private: 150 scoped_refptr<ServiceWorkerContextWrapper> wrapper_; 151}; 152 153class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest, 154 public EmbeddedWorkerInstance::Listener { 155 public: 156 typedef EmbeddedWorkerBrowserTest self; 157 158 EmbeddedWorkerBrowserTest() 159 : last_worker_status_(EmbeddedWorkerInstance::STOPPED) {} 160 virtual ~EmbeddedWorkerBrowserTest() {} 161 162 virtual void TearDownOnIOThread() OVERRIDE { 163 if (worker_) { 164 worker_->RemoveListener(this); 165 worker_.reset(); 166 } 167 } 168 169 void StartOnIOThread() { 170 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 171 worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker(); 172 EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status()); 173 worker_->AddListener(this); 174 175 AssociateRendererProcessToWorker(worker_.get()); 176 177 const int64 service_worker_version_id = 33L; 178 const GURL scope = embedded_test_server()->GetURL("/*"); 179 const GURL script_url = embedded_test_server()->GetURL( 180 "/service_worker/worker.js"); 181 std::vector<int> processes; 182 processes.push_back( 183 shell()->web_contents()->GetRenderProcessHost()->GetID()); 184 worker_->Start( 185 service_worker_version_id, 186 scope, 187 script_url, 188 processes, 189 base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this)); 190 } 191 void StartOnIOThread2(ServiceWorkerStatusCode status) { 192 last_worker_status_ = worker_->status(); 193 EXPECT_EQ(SERVICE_WORKER_OK, status); 194 EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_); 195 196 if (status != SERVICE_WORKER_OK && !done_closure_.is_null()) 197 done_closure_.Run(); 198 } 199 200 void StopOnIOThread() { 201 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 202 EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status()); 203 204 ServiceWorkerStatusCode status = worker_->Stop(); 205 206 last_worker_status_ = worker_->status(); 207 EXPECT_EQ(SERVICE_WORKER_OK, status); 208 EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_); 209 210 if (status != SERVICE_WORKER_OK && !done_closure_.is_null()) 211 done_closure_.Run(); 212 } 213 214 protected: 215 // EmbeddedWorkerInstance::Observer overrides: 216 virtual void OnStarted() OVERRIDE { 217 ASSERT_TRUE(worker_ != NULL); 218 ASSERT_FALSE(done_closure_.is_null()); 219 last_worker_status_ = worker_->status(); 220 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_); 221 } 222 virtual void OnStopped() OVERRIDE { 223 ASSERT_TRUE(worker_ != NULL); 224 ASSERT_FALSE(done_closure_.is_null()); 225 last_worker_status_ = worker_->status(); 226 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_); 227 } 228 virtual void OnReportException(const base::string16& error_message, 229 int line_number, 230 int column_number, 231 const GURL& source_url) OVERRIDE {} 232 virtual void OnReportConsoleMessage(int source_identifier, 233 int message_level, 234 const base::string16& message, 235 int line_number, 236 const GURL& source_url) OVERRIDE {} 237 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 238 return false; 239 } 240 241 scoped_ptr<EmbeddedWorkerInstance> worker_; 242 EmbeddedWorkerInstance::Status last_worker_status_; 243 244 // Called by EmbeddedWorkerInstance::Observer overrides so that 245 // test code can wait for the worker status notifications. 246 base::Closure done_closure_; 247}; 248 249class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest { 250 public: 251 typedef ServiceWorkerVersionBrowserTest self; 252 253 virtual ~ServiceWorkerVersionBrowserTest() {} 254 255 virtual void TearDownOnIOThread() OVERRIDE { 256 registration_ = NULL; 257 version_ = NULL; 258 } 259 260 void InstallTestHelper(const std::string& worker_url, 261 ServiceWorkerStatusCode expected_status) { 262 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this, 263 worker_url)); 264 265 // Dispatch install on a worker. 266 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 267 base::RunLoop install_run_loop; 268 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 269 base::Bind(&self::InstallOnIOThread, this, 270 install_run_loop.QuitClosure(), 271 &status)); 272 install_run_loop.Run(); 273 ASSERT_EQ(expected_status, status); 274 275 // Stop the worker. 276 status = SERVICE_WORKER_ERROR_FAILED; 277 base::RunLoop stop_run_loop; 278 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 279 base::Bind(&self::StopOnIOThread, this, 280 stop_run_loop.QuitClosure(), 281 &status)); 282 stop_run_loop.Run(); 283 ASSERT_EQ(SERVICE_WORKER_OK, status); 284 } 285 286 void ActivateTestHelper( 287 const std::string& worker_url, 288 ServiceWorkerStatusCode expected_status) { 289 RunOnIOThread( 290 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url)); 291 version_->SetStatus(ServiceWorkerVersion::INSTALLED); 292 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 293 base::RunLoop run_loop; 294 BrowserThread::PostTask( 295 BrowserThread::IO, 296 FROM_HERE, 297 base::Bind( 298 &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status)); 299 run_loop.Run(); 300 ASSERT_EQ(expected_status, status); 301 } 302 303 void FetchOnRegisteredWorker(ServiceWorkerFetchEventResult* result, 304 ServiceWorkerResponse* response) { 305 FetchResult fetch_result; 306 fetch_result.status = SERVICE_WORKER_ERROR_FAILED; 307 base::RunLoop fetch_run_loop; 308 BrowserThread::PostTask(BrowserThread::IO, 309 FROM_HERE, 310 base::Bind(&self::FetchOnIOThread, 311 this, 312 fetch_run_loop.QuitClosure(), 313 &fetch_result)); 314 fetch_run_loop.Run(); 315 *result = fetch_result.result; 316 *response = fetch_result.response; 317 ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status); 318 } 319 320 void FetchTestHelper(const std::string& worker_url, 321 ServiceWorkerFetchEventResult* result, 322 ServiceWorkerResponse* response) { 323 RunOnIOThread( 324 base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url)); 325 326 FetchOnRegisteredWorker(result, response); 327 } 328 329 void SetUpRegistrationOnIOThread(const std::string& worker_url) { 330 registration_ = new ServiceWorkerRegistration( 331 embedded_test_server()->GetURL("/*"), 332 embedded_test_server()->GetURL(worker_url), 333 wrapper()->context()->storage()->NewRegistrationId(), 334 wrapper()->context()->AsWeakPtr()); 335 version_ = new ServiceWorkerVersion( 336 registration_, 337 wrapper()->context()->storage()->NewVersionId(), 338 wrapper()->context()->AsWeakPtr()); 339 AssociateRendererProcessToWorker(version_->embedded_worker()); 340 } 341 342 void StartOnIOThread(const base::Closure& done, 343 ServiceWorkerStatusCode* result) { 344 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 345 version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result)); 346 } 347 348 void InstallOnIOThread(const base::Closure& done, 349 ServiceWorkerStatusCode* result) { 350 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 351 version_->DispatchInstallEvent( 352 -1, CreateReceiver(BrowserThread::UI, done, result)); 353 } 354 355 void ActivateOnIOThread(const base::Closure& done, 356 ServiceWorkerStatusCode* result) { 357 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 358 version_->SetStatus(ServiceWorkerVersion::INSTALLED); 359 version_->DispatchActivateEvent( 360 CreateReceiver(BrowserThread::UI, done, result)); 361 } 362 363 void FetchOnIOThread(const base::Closure& done, FetchResult* result) { 364 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 365 ServiceWorkerFetchRequest request( 366 embedded_test_server()->GetURL("/service_worker/empty.html"), 367 "GET", 368 std::map<std::string, std::string>()); 369 version_->SetStatus(ServiceWorkerVersion::ACTIVE); 370 version_->DispatchFetchEvent( 371 request, CreateResponseReceiver(BrowserThread::UI, done, result)); 372 } 373 374 void StopOnIOThread(const base::Closure& done, 375 ServiceWorkerStatusCode* result) { 376 ASSERT_TRUE(version_); 377 version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result)); 378 } 379 380 void SyncEventOnIOThread(const base::Closure& done, 381 ServiceWorkerStatusCode* result) { 382 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 383 version_->SetStatus(ServiceWorkerVersion::ACTIVE); 384 version_->DispatchSyncEvent( 385 CreateReceiver(BrowserThread::UI, done, result)); 386 } 387 388 protected: 389 scoped_refptr<ServiceWorkerRegistration> registration_; 390 scoped_refptr<ServiceWorkerVersion> version_; 391}; 392 393IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) { 394 // Start a worker and wait until OnStarted() is called. 395 base::RunLoop start_run_loop; 396 done_closure_ = start_run_loop.QuitClosure(); 397 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 398 base::Bind(&self::StartOnIOThread, this)); 399 start_run_loop.Run(); 400 401 ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_); 402 403 // Stop a worker and wait until OnStopped() is called. 404 base::RunLoop stop_run_loop; 405 done_closure_ = stop_run_loop.QuitClosure(); 406 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 407 base::Bind(&self::StopOnIOThread, this)); 408 stop_run_loop.Run(); 409 410 ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_); 411} 412 413IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) { 414 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this, 415 "/service_worker/worker.js")); 416 417 // Start a worker. 418 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 419 base::RunLoop start_run_loop; 420 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 421 base::Bind(&self::StartOnIOThread, this, 422 start_run_loop.QuitClosure(), 423 &status)); 424 start_run_loop.Run(); 425 ASSERT_EQ(SERVICE_WORKER_OK, status); 426 427 // Stop the worker. 428 status = SERVICE_WORKER_ERROR_FAILED; 429 base::RunLoop stop_run_loop; 430 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 431 base::Bind(&self::StopOnIOThread, this, 432 stop_run_loop.QuitClosure(), 433 &status)); 434 stop_run_loop.Run(); 435 ASSERT_EQ(SERVICE_WORKER_OK, status); 436} 437 438IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) { 439 RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this, 440 "/service_worker/nonexistent.js")); 441 442 // Start a worker for nonexistent URL. 443 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 444 base::RunLoop start_run_loop; 445 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 446 base::Bind(&self::StartOnIOThread, this, 447 start_run_loop.QuitClosure(), 448 &status)); 449 start_run_loop.Run(); 450 ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status); 451} 452 453IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) { 454 InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK); 455} 456 457IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, 458 InstallWithWaitUntil_Fulfilled) { 459 InstallTestHelper("/service_worker/worker_install_fulfilled.js", 460 SERVICE_WORKER_OK); 461} 462 463IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, 464 Activate_NoEventListener) { 465 ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK); 466 ASSERT_EQ(ServiceWorkerVersion::ACTIVE, version_->status()); 467} 468 469IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) { 470 ActivateTestHelper("/service_worker/worker_activate_rejected.js", 471 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED); 472} 473 474IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, 475 InstallWithWaitUntil_Rejected) { 476 InstallTestHelper("/service_worker/worker_install_rejected.js", 477 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED); 478} 479 480IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) { 481 ServiceWorkerFetchEventResult result; 482 ServiceWorkerResponse response; 483 FetchTestHelper("/service_worker/fetch_event.js", &result, &response); 484 ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result); 485 EXPECT_EQ(301, response.status_code); 486 EXPECT_EQ("Moved Permanently", response.status_text); 487 std::map<std::string, std::string> expected_headers; 488 expected_headers["Content-Language"] = "fi"; 489 expected_headers["Content-Type"] = "text/html; charset=UTF-8"; 490 EXPECT_EQ(expected_headers, response.headers); 491 492 scoped_refptr<ChromeBlobStorageContext> context = 493 ChromeBlobStorageContext::GetFor( 494 shell()->web_contents()->GetBrowserContext()); 495 std::string body; 496 RunOnIOThread( 497 base::Bind(&ReadResponseBody, &body, context, response.blob_uuid)); 498 EXPECT_EQ("This resource is gone. Gone, gone, gone.", body); 499} 500 501IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, 502 SyncAbortedWithoutFlag) { 503 RunOnIOThread(base::Bind( 504 &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js")); 505 506 // Run the sync event. 507 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 508 base::RunLoop sync_run_loop; 509 BrowserThread::PostTask(BrowserThread::IO, 510 FROM_HERE, 511 base::Bind(&self::SyncEventOnIOThread, 512 this, 513 sync_run_loop.QuitClosure(), 514 &status)); 515 sync_run_loop.Run(); 516 ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT, status); 517} 518 519IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) { 520 CommandLine* command_line = CommandLine::ForCurrentProcess(); 521 command_line->AppendSwitch(switches::kEnableServiceWorkerSync); 522 523 RunOnIOThread(base::Bind( 524 &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js")); 525 ServiceWorkerFetchEventResult result; 526 ServiceWorkerResponse response; 527 528 // Should 404 before sync event. 529 FetchOnRegisteredWorker(&result, &response); 530 EXPECT_EQ(404, response.status_code); 531 532 // Run the sync event. 533 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 534 base::RunLoop sync_run_loop; 535 BrowserThread::PostTask(BrowserThread::IO, 536 FROM_HERE, 537 base::Bind(&self::SyncEventOnIOThread, 538 this, 539 sync_run_loop.QuitClosure(), 540 &status)); 541 sync_run_loop.Run(); 542 ASSERT_EQ(SERVICE_WORKER_OK, status); 543 544 // Should 200 after sync event. 545 FetchOnRegisteredWorker(&result, &response); 546 EXPECT_EQ(200, response.status_code); 547} 548 549class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest { 550 public: 551 typedef ServiceWorkerBlackBoxBrowserTest self; 552 553 static void ExpectResultAndRun(bool expected, 554 const base::Closure& continuation, 555 bool actual) { 556 EXPECT_EQ(expected, actual); 557 continuation.Run(); 558 } 559 560 void FindRegistrationOnIO(const GURL& document_url, 561 ServiceWorkerStatusCode* status, 562 GURL* script_url, 563 const base::Closure& continuation) { 564 wrapper()->context()->storage()->FindRegistrationForDocument( 565 document_url, 566 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2, 567 this, 568 status, 569 script_url, 570 continuation)); 571 } 572 573 void FindRegistrationOnIO2( 574 ServiceWorkerStatusCode* out_status, 575 GURL* script_url, 576 const base::Closure& continuation, 577 ServiceWorkerStatusCode status, 578 const scoped_refptr<ServiceWorkerRegistration>& registration) { 579 *out_status = status; 580 if (registration) { 581 *script_url = registration->script_url(); 582 } else { 583 EXPECT_NE(SERVICE_WORKER_OK, status); 584 } 585 continuation.Run(); 586 } 587}; 588 589static int CountRenderProcessHosts() { 590 int result = 0; 591 for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator()); 592 !iter.IsAtEnd(); 593 iter.Advance()) { 594 result++; 595 } 596 return result; 597} 598 599IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, Registration) { 600 // Close the only window to be sure we're not re-using its RenderProcessHost. 601 shell()->Close(); 602 EXPECT_EQ(0, CountRenderProcessHosts()); 603 604 const std::string kWorkerUrl = "/service_worker/fetch_event.js"; 605 606 // Unregistering nothing should return true. 607 { 608 base::RunLoop run_loop; 609 public_context()->UnregisterServiceWorker( 610 embedded_test_server()->GetURL("/*"), 611 base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun, 612 true, 613 run_loop.QuitClosure())); 614 run_loop.Run(); 615 } 616 617 // If we use a worker URL that doesn't exist, registration fails. 618 { 619 base::RunLoop run_loop; 620 public_context()->RegisterServiceWorker( 621 embedded_test_server()->GetURL("/*"), 622 embedded_test_server()->GetURL("/does/not/exist"), 623 base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun, 624 false, 625 run_loop.QuitClosure())); 626 run_loop.Run(); 627 } 628 EXPECT_EQ(0, CountRenderProcessHosts()); 629 630 // Register returns when the promise would be resolved. 631 { 632 base::RunLoop run_loop; 633 public_context()->RegisterServiceWorker( 634 embedded_test_server()->GetURL("/*"), 635 embedded_test_server()->GetURL(kWorkerUrl), 636 base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun, 637 true, 638 run_loop.QuitClosure())); 639 run_loop.Run(); 640 } 641 EXPECT_EQ(1, CountRenderProcessHosts()); 642 643 // Registering again should succeed, although the algo still 644 // might not be complete. 645 { 646 base::RunLoop run_loop; 647 public_context()->RegisterServiceWorker( 648 embedded_test_server()->GetURL("/*"), 649 embedded_test_server()->GetURL(kWorkerUrl), 650 base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun, 651 true, 652 run_loop.QuitClosure())); 653 run_loop.Run(); 654 } 655 656 // The registration algo might not be far enough along to have 657 // stored the registration data, so it may not be findable 658 // at this point. 659 660 // Unregistering something should return true. 661 { 662 base::RunLoop run_loop; 663 public_context()->UnregisterServiceWorker( 664 embedded_test_server()->GetURL("/*"), 665 base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun, 666 true, 667 run_loop.QuitClosure())); 668 run_loop.Run(); 669 } 670 EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the " 671 "workers eagerly, so their RPHs " 672 "can still be running."; 673 674 // Should not be able to find it. 675 { 676 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED; 677 GURL script_url; 678 RunOnIOThread( 679 base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO, 680 this, 681 embedded_test_server()->GetURL("/service_worker/empty.html"), 682 &status, 683 &script_url)); 684 EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status); 685 } 686} 687 688} // namespace content 689