Index: content/browser/service_worker/service_worker_dispatcher_host_unittest.cc |
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc |
index 9bce9aec5328300bd91f5d067ca8a609fd861709..d8a370af8bf8414b14eba126e477b64f01c59082 100644 |
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc |
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc |
@@ -11,11 +11,13 @@ |
#include "base/files/file_path.h" |
#include "base/run_loop.h" |
#include "content/browser/browser_thread_impl.h" |
+#include "content/browser/message_port_service.h" |
#include "content/browser/service_worker/embedded_worker_instance.h" |
#include "content/browser/service_worker/embedded_worker_registry.h" |
#include "content/browser/service_worker/embedded_worker_test_helper.h" |
#include "content/browser/service_worker/service_worker_context_core.h" |
#include "content/browser/service_worker/service_worker_context_wrapper.h" |
+#include "content/browser/service_worker/service_worker_handle.h" |
#include "content/common/service_worker/embedded_worker_messages.h" |
#include "content/common/service_worker/service_worker_messages.h" |
#include "content/public/common/content_switches.h" |
@@ -35,8 +37,17 @@ static void SaveStatusCallback(bool* called, |
*out = status; |
} |
+void SetUpDummyMessagePort(std::vector<TransferredMessagePort>* ports) { |
+ int port_id = -1; |
+ MessagePortService::GetInstance()->Create(MSG_ROUTING_NONE, nullptr, |
+ &port_id); |
+ TransferredMessagePort dummy_port; |
+ dummy_port.id = port_id; |
+ ports->push_back(dummy_port); |
} |
+} // namespace |
+ |
static const int kRenderFrameId = 1; |
class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { |
@@ -65,25 +76,81 @@ class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { |
~TestingServiceWorkerDispatcherHost() override {} |
}; |
+class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper { |
+ public: |
+ FailToStartWorkerTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} |
+ |
+ void OnStartWorker(int embedded_worker_id, |
+ int64_t service_worker_version_id, |
+ const GURL& scope, |
+ const GURL& script_url, |
+ bool pause_after_download) override { |
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); |
+ registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id); |
+ } |
+}; |
+ |
class ServiceWorkerDispatcherHostTest : public testing::Test { |
protected: |
ServiceWorkerDispatcherHostTest() |
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} |
void SetUp() override { |
- helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath())); |
- dispatcher_host_ = new TestingServiceWorkerDispatcherHost( |
- helper_->mock_render_process_id(), context_wrapper(), |
- &resource_context_, helper_.get()); |
+ Initialize(make_scoped_ptr(new EmbeddedWorkerTestHelper(base::FilePath()))); |
} |
- void TearDown() override { helper_.reset(); } |
+ void TearDown() override { |
+ version_ = nullptr; |
+ registration_ = nullptr; |
+ helper_.reset(); |
+ } |
ServiceWorkerContextCore* context() { return helper_->context(); } |
ServiceWorkerContextWrapper* context_wrapper() { |
return helper_->context_wrapper(); |
} |
+ void Initialize(scoped_ptr<EmbeddedWorkerTestHelper> helper) { |
+ helper_.reset(helper.release()); |
+ dispatcher_host_ = new TestingServiceWorkerDispatcherHost( |
+ helper_->mock_render_process_id(), context_wrapper(), |
+ &resource_context_, helper_.get()); |
+ } |
+ |
+ void SetUpRegistration(const GURL& scope, const GURL& script_url) { |
+ registration_ = new ServiceWorkerRegistration( |
+ scope, 1L, helper_->context()->AsWeakPtr()); |
+ version_ = new ServiceWorkerVersion(registration_.get(), script_url, 1L, |
+ helper_->context()->AsWeakPtr()); |
+ std::vector<ServiceWorkerDatabase::ResourceRecord> records; |
+ records.push_back( |
+ ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100)); |
+ version_->script_cache_map()->SetResources(records); |
+ |
+ // Make the registration findable via storage functions. |
+ helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); |
+ base::RunLoop().RunUntilIdle(); |
+ bool called = false; |
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; |
+ helper_->context()->storage()->StoreRegistration( |
+ registration_.get(), version_.get(), |
+ base::Bind(&SaveStatusCallback, &called, &status)); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_TRUE(called); |
+ EXPECT_EQ(SERVICE_WORKER_OK, status); |
+ } |
+ |
+ void SendProviderCreated(ServiceWorkerProviderType type, |
+ const GURL& pattern) { |
+ const int64_t kProviderId = 99; |
+ dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( |
+ kProviderId, MSG_ROUTING_NONE, type)); |
+ helper_->SimulateAddProcessToPattern(pattern, |
+ helper_->mock_render_process_id()); |
+ provider_host_ = context()->GetProviderHost( |
+ helper_->mock_render_process_id(), kProviderId); |
+ } |
+ |
void SendRegister(int64_t provider_id, GURL pattern, GURL worker_url) { |
dispatcher_host_->OnMessageReceived( |
ServiceWorkerHostMsg_RegisterServiceWorker( |
@@ -146,6 +213,18 @@ class ServiceWorkerDispatcherHostTest : public testing::Test { |
dispatcher_host_->ipc_sink()->ClearMessages(); |
} |
+ void DispatchExtendableMessageEvent( |
+ scoped_refptr<ServiceWorkerVersion> worker, |
+ const base::string16& message, |
+ const url::Origin& source_origin, |
+ const std::vector<TransferredMessagePort>& sent_message_ports, |
+ ServiceWorkerProviderHost* sender_provider_host, |
+ const ServiceWorkerDispatcherHost::StatusCallback& callback) { |
+ dispatcher_host_->DispatchExtendableMessageEvent( |
+ std::move(worker), message, source_origin, sent_message_ports, |
+ sender_provider_host, callback); |
+ } |
+ |
ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) { |
return new ServiceWorkerProviderHost( |
helper_->mock_render_process_id(), kRenderFrameId, provider_id, |
@@ -153,11 +232,13 @@ class ServiceWorkerDispatcherHostTest : public testing::Test { |
dispatcher_host_.get()); |
} |
- |
TestBrowserThreadBundle browser_thread_bundle_; |
content::MockResourceContext resource_context_; |
scoped_ptr<EmbeddedWorkerTestHelper> helper_; |
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; |
+ scoped_refptr<ServiceWorkerRegistration> registration_; |
+ scoped_refptr<ServiceWorkerVersion> version_; |
+ ServiceWorkerProviderHost* provider_host_; |
}; |
class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient { |
@@ -526,61 +607,33 @@ TEST_F(ServiceWorkerDispatcherHostTest, GetRegistrations_EarlyContextDeletion) { |
} |
TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) { |
+ GURL pattern = GURL("http://www.example.com/"); |
+ GURL script_url = GURL("http://www.example.com/service_worker.js"); |
int process_id = helper_->mock_render_process_id(); |
- // Add a provider and worker. |
- const int64_t kProviderId = 99; // Dummy value |
- dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( |
- kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); |
+ SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_WINDOW, pattern); |
+ SetUpRegistration(pattern, script_url); |
+ int64_t provider_id = provider_host_->provider_id(); |
- GURL pattern = GURL("http://www.example.com/"); |
- scoped_refptr<ServiceWorkerRegistration> registration( |
- new ServiceWorkerRegistration(pattern, |
- 1L, |
- helper_->context()->AsWeakPtr())); |
- scoped_refptr<ServiceWorkerVersion> version( |
- new ServiceWorkerVersion(registration.get(), |
- GURL("http://www.example.com/service_worker.js"), |
- 1L, |
- helper_->context()->AsWeakPtr())); |
- std::vector<ServiceWorkerDatabase::ResourceRecord> records; |
- records.push_back( |
- ServiceWorkerDatabase::ResourceRecord(10, version->script_url(), 100)); |
- version->script_cache_map()->SetResources(records); |
- |
- // Make the registration findable via storage functions. |
- helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); |
- base::RunLoop().RunUntilIdle(); |
+ // Start up the worker. |
bool called = false; |
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT; |
- helper_->context()->storage()->StoreRegistration( |
- registration.get(), |
- version.get(), |
- base::Bind(&SaveStatusCallback, &called, &status)); |
- base::RunLoop().RunUntilIdle(); |
- EXPECT_TRUE(called); |
- ASSERT_EQ(SERVICE_WORKER_OK, status); |
- |
- helper_->SimulateAddProcessToPattern(pattern, process_id); |
- |
- // Start up the worker. |
- status = SERVICE_WORKER_ERROR_ABORT; |
- version->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, |
- base::Bind(&SaveStatusCallback, &called, &status)); |
+ version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, |
+ base::Bind(&SaveStatusCallback, &called, &status)); |
base::RunLoop().RunUntilIdle(); |
EXPECT_TRUE(called); |
EXPECT_EQ(SERVICE_WORKER_OK, status); |
- EXPECT_TRUE(context()->GetProviderHost(process_id, kProviderId)); |
- EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status()); |
+ EXPECT_TRUE(context()->GetProviderHost(process_id, provider_id)); |
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status()); |
// Simulate the render process crashing. |
dispatcher_host_->OnFilterRemoved(); |
// The dispatcher host should clean up the state from the process. |
- EXPECT_FALSE(context()->GetProviderHost(process_id, kProviderId)); |
- EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status()); |
+ EXPECT_FALSE(context()->GetProviderHost(process_id, provider_id)); |
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status()); |
// We should be able to hook up a new dispatcher host although the old object |
// is not yet destroyed. This is what the browser does when reusing a crashed |
@@ -593,8 +646,89 @@ TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) { |
// the old dispatcher cleaned up the old provider host, the new one won't |
// complain. |
new_dispatcher_host->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( |
- kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); |
+ provider_id, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); |
EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_); |
} |
+TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent) { |
+ GURL pattern = GURL("http://www.example.com/"); |
+ GURL script_url = GURL("http://www.example.com/service_worker.js"); |
+ |
+ SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, pattern); |
+ SetUpRegistration(pattern, script_url); |
+ |
+ // Set the running hosted version so that we can retrieve a valid service |
+ // worker object information for the source attribute of the message event. |
+ provider_host_->running_hosted_version_ = version_; |
+ |
+ // Set aside the initial refcount of the worker handle. |
+ provider_host_->GetOrCreateServiceWorkerHandle(version_.get()); |
+ ServiceWorkerHandle* sender_worker_handle = |
+ dispatcher_host_->FindServiceWorkerHandle(provider_host_->provider_id(), |
+ version_->version_id()); |
+ const int ref_count = sender_worker_handle->ref_count(); |
+ |
+ // Dispatch ExtendableMessageEvent. |
+ std::vector<TransferredMessagePort> ports; |
+ SetUpDummyMessagePort(&ports); |
+ bool called = false; |
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; |
+ DispatchExtendableMessageEvent( |
+ version_, base::string16(), url::Origin(version_->scope().GetOrigin()), |
+ ports, provider_host_, base::Bind(&SaveStatusCallback, &called, &status)); |
+ for (TransferredMessagePort port : ports) |
+ EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); |
+ EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_TRUE(called); |
+ EXPECT_EQ(SERVICE_WORKER_OK, status); |
+ |
+ // Messages should be held until ports are created at the destination. |
+ for (TransferredMessagePort port : ports) |
+ EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); |
+ |
+ EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); |
+} |
+ |
+TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent_Fail) { |
+ GURL pattern = GURL("http://www.example.com/"); |
+ GURL script_url = GURL("http://www.example.com/service_worker.js"); |
+ |
+ Initialize(make_scoped_ptr(new FailToStartWorkerTestHelper)); |
+ SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, pattern); |
+ SetUpRegistration(pattern, script_url); |
+ |
+ // Set the running hosted version so that we can retrieve a valid service |
+ // worker object information for the source attribute of the message event. |
+ provider_host_->running_hosted_version_ = version_; |
+ |
+ // Set aside the initial refcount of the worker handle. |
+ provider_host_->GetOrCreateServiceWorkerHandle(version_.get()); |
+ ServiceWorkerHandle* sender_worker_handle = |
+ dispatcher_host_->FindServiceWorkerHandle(provider_host_->provider_id(), |
+ version_->version_id()); |
+ const int ref_count = sender_worker_handle->ref_count(); |
+ |
+ // Try to dispatch ExtendableMessageEvent. This should fail to start the |
+ // worker and to dispatch the event. |
+ std::vector<TransferredMessagePort> ports; |
+ SetUpDummyMessagePort(&ports); |
+ bool called = false; |
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; |
+ DispatchExtendableMessageEvent( |
+ version_, base::string16(), url::Origin(version_->scope().GetOrigin()), |
+ ports, provider_host_, base::Bind(&SaveStatusCallback, &called, &status)); |
+ for (TransferredMessagePort port : ports) |
+ EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); |
+ EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_TRUE(called); |
+ EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status); |
+ |
+ // The error callback should clean up the ports and handle. |
+ for (TransferredMessagePort port : ports) |
+ EXPECT_FALSE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); |
+ EXPECT_EQ(ref_count, sender_worker_handle->ref_count()); |
+} |
+ |
} // namespace content |