summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhoro@chromium.org <horo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-13 05:16:01 +0000
committerhoro@chromium.org <horo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-13 05:16:01 +0000
commit3efa9da0caa0c5083092447c5a4884a553d7e6de (patch)
treec5465a6a0e87dfc367824e60ab4a74dc7f341e0e
parentcebea66620040c8eba07aa5bae579a413c159d1a (diff)
downloadchromium_src-3efa9da0caa0c5083092447c5a4884a553d7e6de.zip
chromium_src-3efa9da0caa0c5083092447c5a4884a553d7e6de.tar.gz
chromium_src-3efa9da0caa0c5083092447c5a4884a553d7e6de.tar.bz2
Add SharedWorkerServiceImpl::CheckWorkerDependency().
This method checks the worker dependency of renderer processes and calls IncrementWorkerRefCount and DecrementWorkerRefCount of RenderProcessHostImpl on UI thread if necessary. The old cl (http://crrev.com/256305) was reverted (http://crrev.com/256323) because of the memory leak in MockMessagePortMessageFilter::Send and MockSharedWorkerMessageFilter::Send. This cl has fixed it. The difference between this cl and the old cl is the null value handling of message_queue_ in MockMessagePortMessageFilter::Send and MockSharedWorkerMessageFilter::Send. BUG=327256,351492 TBR=jochen@chromium.org Review URL: https://codereview.chromium.org/196483003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@256749 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/message_port_message_filter.h9
-rw-r--r--content/browser/shared_worker/shared_worker_host.cc1
-rw-r--r--content/browser/shared_worker/shared_worker_message_filter.h7
-rw-r--r--content/browser/shared_worker/shared_worker_service_impl.cc110
-rw-r--r--content/browser/shared_worker/shared_worker_service_impl.h23
-rw-r--r--content/browser/shared_worker/shared_worker_service_impl_unittest.cc594
-rw-r--r--content/content_tests.gypi1
7 files changed, 736 insertions, 9 deletions
diff --git a/content/browser/message_port_message_filter.h b/content/browser/message_port_message_filter.h
index 0dd38c9..5cc191e 100644
--- a/content/browser/message_port_message_filter.h
+++ b/content/browser/message_port_message_filter.h
@@ -6,13 +6,14 @@
#define CONTENT_BROWSER_MESSAGE_PORT_MESSAGE_FILTER_H_
#include "base/callback.h"
+#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
namespace content {
// Filter for MessagePort related IPC messages (creating and destroying a
// MessagePort, sending a message via a MessagePort etc).
-class MessagePortMessageFilter : public BrowserMessageFilter {
+class CONTENT_EXPORT MessagePortMessageFilter : public BrowserMessageFilter {
public:
typedef base::Callback<int(void)> NextRoutingIDCallback;
@@ -28,12 +29,14 @@ class MessagePortMessageFilter : public BrowserMessageFilter {
int GetNextRoutingID();
+ protected:
+ // This is protected, so we can define sub classes for testing.
+ virtual ~MessagePortMessageFilter();
+
private:
friend class BrowserThread;
friend class base::DeleteHelper<MessagePortMessageFilter>;
- virtual ~MessagePortMessageFilter();
-
// Message handlers.
void OnCreateMessagePort(int* route_id, int* message_port_id);
diff --git a/content/browser/shared_worker/shared_worker_host.cc b/content/browser/shared_worker/shared_worker_host.cc
index ac1d606..eb58399 100644
--- a/content/browser/shared_worker/shared_worker_host.cc
+++ b/content/browser/shared_worker/shared_worker_host.cc
@@ -137,7 +137,6 @@ void SharedWorkerHost::WorkerContextDestroyed() {
void SharedWorkerHost::WorkerScriptLoaded() {
// TODO(horo): implement this.
- NOTIMPLEMENTED();
}
void SharedWorkerHost::WorkerScriptLoadFailed() {
diff --git a/content/browser/shared_worker/shared_worker_message_filter.h b/content/browser/shared_worker/shared_worker_message_filter.h
index 285f821..7ca41c2 100644
--- a/content/browser/shared_worker/shared_worker_message_filter.h
+++ b/content/browser/shared_worker/shared_worker_message_filter.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_SHARED_WORKER_SHARED_WORKER_MESSAGE_FILTER_H_
#include "content/browser/worker_host/worker_storage_partition.h"
+#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
class GURL;
@@ -17,7 +18,7 @@ class ResourceContext;
// If "enable-embedded-shared-worker" is set this class will be used instead of
// WorkerMessageFilter.
-class SharedWorkerMessageFilter : public BrowserMessageFilter {
+class CONTENT_EXPORT SharedWorkerMessageFilter : public BrowserMessageFilter {
public:
SharedWorkerMessageFilter(int render_process_id,
ResourceContext* resource_context,
@@ -36,9 +37,11 @@ class SharedWorkerMessageFilter : public BrowserMessageFilter {
return message_port_message_filter_;
}
- private:
+ protected:
+ // This is protected, so we can define sub classes for testing.
virtual ~SharedWorkerMessageFilter();
+ private:
// Message handlers.
void OnCreateWorker(const ViewHostMsg_CreateWorker_Params& params,
int* route_id);
diff --git a/content/browser/shared_worker/shared_worker_service_impl.cc b/content/browser/shared_worker/shared_worker_service_impl.cc
index 8ba7eed..e48add9 100644
--- a/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -4,6 +4,12 @@
#include "content/browser/shared_worker/shared_worker_service_impl.h"
+#include <algorithm>
+#include <iterator>
+#include <set>
+#include <vector>
+
+#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/shared_worker/shared_worker_host.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
#include "content/browser/shared_worker/shared_worker_message_filter.h"
@@ -14,16 +20,64 @@
#include "content/public/browser/worker_service_observer.h"
namespace content {
+namespace {
+
+class ScopedWorkerDependencyChecker {
+ public:
+ explicit ScopedWorkerDependencyChecker(SharedWorkerServiceImpl* service)
+ : service_(service) {}
+ ~ScopedWorkerDependencyChecker() { service_->CheckWorkerDependency(); }
+
+ private:
+ SharedWorkerServiceImpl* service_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedWorkerDependencyChecker);
+};
+
+void UpdateWorkerDependencyOnUI(const std::vector<int>& added_ids,
+ const std::vector<int>& removed_ids) {
+ for (size_t i = 0; i < added_ids.size(); ++i) {
+ RenderProcessHostImpl* render_process_host_impl =
+ static_cast<RenderProcessHostImpl*>(
+ RenderProcessHost::FromID(added_ids[i]));
+ if (!render_process_host_impl)
+ continue;
+ render_process_host_impl->IncrementWorkerRefCount();
+ }
+ for (size_t i = 0; i < removed_ids.size(); ++i) {
+ RenderProcessHostImpl* render_process_host_impl =
+ static_cast<RenderProcessHostImpl*>(
+ RenderProcessHost::FromID(removed_ids[i]));
+ if (!render_process_host_impl)
+ continue;
+ render_process_host_impl->DecrementWorkerRefCount();
+ }
+}
+
+void UpdateWorkerDependency(const std::vector<int>& added_ids,
+ const std::vector<int>& removed_ids) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&UpdateWorkerDependencyOnUI, added_ids, removed_ids));
+}
+
+} // namespace
SharedWorkerServiceImpl* SharedWorkerServiceImpl::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
return Singleton<SharedWorkerServiceImpl>::get();
}
-SharedWorkerServiceImpl::SharedWorkerServiceImpl() {
-}
+SharedWorkerServiceImpl::SharedWorkerServiceImpl()
+ : update_worker_dependency_(UpdateWorkerDependency) {}
-SharedWorkerServiceImpl::~SharedWorkerServiceImpl() {
+SharedWorkerServiceImpl::~SharedWorkerServiceImpl() {}
+
+void SharedWorkerServiceImpl::ResetForTesting() {
+ last_worker_depended_renderers_.clear();
+ worker_hosts_.clear();
+ observers_.Clear();
+ update_worker_dependency_ = UpdateWorkerDependency;
}
bool SharedWorkerServiceImpl::TerminateWorker(int process_id, int route_id) {
@@ -73,6 +127,7 @@ void SharedWorkerServiceImpl::CreateWorker(
const WorkerStoragePartition& partition,
bool* url_mismatch) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ScopedWorkerDependencyChecker checker(this);
*url_mismatch = false;
SharedWorkerInstance* existing_instance =
FindSharedWorkerInstance(
@@ -135,6 +190,7 @@ void SharedWorkerServiceImpl::ForwardToWorker(
void SharedWorkerServiceImpl::DocumentDetached(
unsigned long long document_id,
SharedWorkerMessageFilter* filter) {
+ ScopedWorkerDependencyChecker checker(this);
for (WorkerHostMap::const_iterator iter = worker_hosts_.begin();
iter != worker_hosts_.end();
++iter) {
@@ -145,6 +201,7 @@ void SharedWorkerServiceImpl::DocumentDetached(
void SharedWorkerServiceImpl::WorkerContextClosed(
int worker_route_id,
SharedWorkerMessageFilter* filter) {
+ ScopedWorkerDependencyChecker checker(this);
if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
host->WorkerContextClosed();
}
@@ -152,6 +209,7 @@ void SharedWorkerServiceImpl::WorkerContextClosed(
void SharedWorkerServiceImpl::WorkerContextDestroyed(
int worker_route_id,
SharedWorkerMessageFilter* filter) {
+ ScopedWorkerDependencyChecker checker(this);
scoped_ptr<SharedWorkerHost> host =
worker_hosts_.take_and_erase(std::make_pair(filter->render_process_id(),
worker_route_id));
@@ -170,6 +228,7 @@ void SharedWorkerServiceImpl::WorkerScriptLoaded(
void SharedWorkerServiceImpl::WorkerScriptLoadFailed(
int worker_route_id,
SharedWorkerMessageFilter* filter) {
+ ScopedWorkerDependencyChecker checker(this);
scoped_ptr<SharedWorkerHost> host =
worker_hosts_.take_and_erase(std::make_pair(filter->render_process_id(),
worker_route_id));
@@ -219,6 +278,7 @@ void SharedWorkerServiceImpl::AllowIndexedDB(
void SharedWorkerServiceImpl::OnSharedWorkerMessageFilterClosing(
SharedWorkerMessageFilter* filter) {
+ ScopedWorkerDependencyChecker checker(this);
std::vector<ProcessRouteIdPair> remove_list;
for (WorkerHostMap::iterator iter = worker_hosts_.begin();
iter != worker_hosts_.end();
@@ -253,4 +313,48 @@ SharedWorkerInstance* SharedWorkerServiceImpl::FindSharedWorkerInstance(
return NULL;
}
+const std::set<int>
+SharedWorkerServiceImpl::GetRenderersWithWorkerDependency() {
+ std::set<int> dependent_renderers;
+ for (WorkerHostMap::iterator host_iter = worker_hosts_.begin();
+ host_iter != worker_hosts_.end();
+ ++host_iter) {
+ const int process_id = host_iter->first.first;
+ if (dependent_renderers.count(process_id))
+ continue;
+ SharedWorkerInstance* instance = host_iter->second->instance();
+ if (instance &&
+ instance->worker_document_set()->ContainsExternalRenderer(process_id)) {
+ dependent_renderers.insert(process_id);
+ }
+ }
+ return dependent_renderers;
+}
+
+void SharedWorkerServiceImpl::CheckWorkerDependency() {
+ const std::set<int> current_worker_depended_renderers =
+ GetRenderersWithWorkerDependency();
+ std::vector<int> added_items;
+ std::vector<int> removed_items;
+ std::set_difference(current_worker_depended_renderers.begin(),
+ current_worker_depended_renderers.end(),
+ last_worker_depended_renderers_.begin(),
+ last_worker_depended_renderers_.end(),
+ std::back_inserter(added_items));
+ std::set_difference(last_worker_depended_renderers_.begin(),
+ last_worker_depended_renderers_.end(),
+ current_worker_depended_renderers.begin(),
+ current_worker_depended_renderers.end(),
+ std::back_inserter(removed_items));
+ if (!added_items.empty() || !removed_items.empty()) {
+ last_worker_depended_renderers_ = current_worker_depended_renderers;
+ update_worker_dependency_(added_items, removed_items);
+ }
+}
+
+void SharedWorkerServiceImpl::ChangeUpdateWorkerDependencyFuncForTesting(
+ UpdateWorkerDependencyFunc new_func) {
+ update_worker_dependency_ = new_func;
+}
+
} // namespace content
diff --git a/content/browser/shared_worker/shared_worker_service_impl.h b/content/browser/shared_worker/shared_worker_service_impl.h
index fd19989..a60ec70 100644
--- a/content/browser/shared_worker/shared_worker_service_impl.h
+++ b/content/browser/shared_worker/shared_worker_service_impl.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_SHARED_WORKER_SHARED_WORKER_SERVICE_IMPL_H_
#define CONTENT_BROWSER_SHARED_WORKER_SHARED_WORKER_SERVICE_IMPL_H_
+#include <set>
+
#include "base/compiler_specific.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/singleton.h"
@@ -85,12 +87,23 @@ class CONTENT_EXPORT SharedWorkerServiceImpl
void OnSharedWorkerMessageFilterClosing(
SharedWorkerMessageFilter* filter);
+ // Checks the worker dependency of renderer processes and calls
+ // IncrementWorkerRefCount and DecrementWorkerRefCount of
+ // RenderProcessHostImpl on UI thread if necessary.
+ void CheckWorkerDependency();
+
private:
friend struct DefaultSingletonTraits<SharedWorkerServiceImpl>;
+ friend class SharedWorkerServiceImplTest;
+
+ typedef void (*UpdateWorkerDependencyFunc)(const std::vector<int>&,
+ const std::vector<int>&);
SharedWorkerServiceImpl();
virtual ~SharedWorkerServiceImpl();
+ void ResetForTesting();
+
SharedWorkerHost* FindSharedWorkerHost(
SharedWorkerMessageFilter* filter,
int worker_route_id);
@@ -101,6 +114,16 @@ class CONTENT_EXPORT SharedWorkerServiceImpl
const WorkerStoragePartition& worker_partition,
ResourceContext* resource_context);
+ // Returns the IDs of the renderer processes which are executing
+ // SharedWorkers connected to other renderer processes.
+ const std::set<int> GetRenderersWithWorkerDependency();
+
+ void ChangeUpdateWorkerDependencyFuncForTesting(
+ UpdateWorkerDependencyFunc new_func);
+
+ std::set<int> last_worker_depended_renderers_;
+ UpdateWorkerDependencyFunc update_worker_dependency_;
+
// Pair of render_process_id and worker_route_id.
typedef std::pair<int, int> ProcessRouteIdPair;
typedef base::ScopedPtrHashMap<ProcessRouteIdPair,
diff --git a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
new file mode 100644
index 0000000..112b8e8
--- /dev/null
+++ b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
@@ -0,0 +1,594 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <map>
+#include <vector>
+
+#include "base/atomic_sequence_num.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/message_port_message_filter.h"
+#include "content/browser/shared_worker/shared_worker_message_filter.h"
+#include "content/browser/shared_worker/shared_worker_service_impl.h"
+#include "content/browser/worker_host/worker_storage_partition.h"
+#include "content/common/message_port_messages.h"
+#include "content/common/view_messages.h"
+#include "content/common/worker_messages.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "ipc/ipc_sync_message.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+class MockMessagePortMessageFilter : public MessagePortMessageFilter {
+ public:
+ MockMessagePortMessageFilter(const NextRoutingIDCallback& callback,
+ ScopedVector<IPC::Message>* message_queue)
+ : MessagePortMessageFilter(callback), message_queue_(message_queue) {}
+
+ virtual bool Send(IPC::Message* message) OVERRIDE {
+ if (!message_queue_) {
+ delete message;
+ return false;
+ }
+ message_queue_->push_back(message);
+ return true;
+ }
+
+ void Close() {
+ message_queue_ = NULL;
+ OnChannelClosing();
+ }
+
+ private:
+ virtual ~MockMessagePortMessageFilter() {}
+ ScopedVector<IPC::Message>* message_queue_;
+};
+
+class MockSharedWorkerMessageFilter : public SharedWorkerMessageFilter {
+ public:
+ MockSharedWorkerMessageFilter(int render_process_id,
+ ResourceContext* resource_context,
+ const WorkerStoragePartition& partition,
+ MessagePortMessageFilter* message_port_filter,
+ ScopedVector<IPC::Message>* message_queue)
+ : SharedWorkerMessageFilter(render_process_id,
+ resource_context,
+ partition,
+ message_port_filter),
+ message_queue_(message_queue) {}
+
+ virtual bool Send(IPC::Message* message) OVERRIDE {
+ if (!message_queue_) {
+ delete message;
+ return false;
+ }
+ message_queue_->push_back(message);
+ return true;
+ }
+
+ void Close() {
+ message_queue_ = NULL;
+ OnChannelClosing();
+ }
+
+ private:
+ virtual ~MockSharedWorkerMessageFilter() {}
+ ScopedVector<IPC::Message>* message_queue_;
+};
+
+class MockRendererProcessHost {
+ public:
+ MockRendererProcessHost(int process_id,
+ ResourceContext* resource_context,
+ const WorkerStoragePartition& partition)
+ : message_filter_(new MockMessagePortMessageFilter(
+ base::Bind(&base::AtomicSequenceNumber::GetNext,
+ base::Unretained(&next_routing_id_)),
+ &queued_messages_)),
+ worker_filter_(new MockSharedWorkerMessageFilter(process_id,
+ resource_context,
+ partition,
+ message_filter_.get(),
+ &queued_messages_)) {}
+
+ ~MockRendererProcessHost() {
+ message_filter_->Close();
+ worker_filter_->Close();
+ }
+
+ bool OnMessageReceived(IPC::Message* message) {
+ scoped_ptr<IPC::Message> msg(message);
+ bool message_was_ok = false;
+ const bool ret =
+ message_filter_->OnMessageReceived(*message, &message_was_ok) ||
+ worker_filter_->OnMessageReceived(*message, &message_was_ok);
+ if (message->is_sync()) {
+ CHECK(!queued_messages_.empty());
+ const IPC::Message* response_msg = queued_messages_.back();
+ IPC::SyncMessage* sync_msg = static_cast<IPC::SyncMessage*>(message);
+ scoped_ptr<IPC::MessageReplyDeserializer> reply_serializer(
+ sync_msg->GetReplyDeserializer());
+ bool result = reply_serializer->SerializeOutputParameters(*response_msg);
+ CHECK(result);
+ queued_messages_.pop_back();
+ }
+ return ret;
+ }
+
+ size_t QueuedMessageCount() const { return queued_messages_.size(); }
+
+ scoped_ptr<IPC::Message> PopMessage() {
+ CHECK(queued_messages_.size());
+ scoped_ptr<IPC::Message> msg(*queued_messages_.begin());
+ queued_messages_.weak_erase(queued_messages_.begin());
+ return msg.Pass();
+ }
+
+ private:
+ ScopedVector<IPC::Message> queued_messages_;
+ base::AtomicSequenceNumber next_routing_id_;
+ scoped_refptr<MockMessagePortMessageFilter> message_filter_;
+ scoped_refptr<MockSharedWorkerMessageFilter> worker_filter_;
+};
+
+void CreateMessagePortPair(MockRendererProcessHost* renderer,
+ int* route_1,
+ int* port_1,
+ int* route_2,
+ int* port_2) {
+ EXPECT_TRUE(renderer->OnMessageReceived(
+ new MessagePortHostMsg_CreateMessagePort(route_1, port_1)));
+ EXPECT_TRUE(renderer->OnMessageReceived(
+ new MessagePortHostMsg_CreateMessagePort(route_2, port_2)));
+ EXPECT_TRUE(renderer->OnMessageReceived(
+ new MessagePortHostMsg_Entangle(*port_1, *port_2)));
+ EXPECT_TRUE(renderer->OnMessageReceived(
+ new MessagePortHostMsg_Entangle(*port_2, *port_1)));
+}
+
+void PostCreateWorker(MockRendererProcessHost* renderer,
+ const std::string& url,
+ const std::string& name,
+ unsigned long long document_id,
+ int render_frame_route_id,
+ int* connector_route_id) {
+ ViewHostMsg_CreateWorker_Params params;
+ params.url = GURL(url);
+ params.name = base::ASCIIToUTF16(name);
+ params.content_security_policy = base::string16();
+ params.security_policy_type = blink::WebContentSecurityPolicyTypeReport;
+ params.document_id = document_id;
+ params.render_frame_route_id = render_frame_route_id;
+ EXPECT_TRUE(renderer->OnMessageReceived(
+ new ViewHostMsg_CreateWorker(params, connector_route_id)));
+}
+
+class MockSharedWorkerConnector {
+ public:
+ MockSharedWorkerConnector(MockRendererProcessHost* renderer_host)
+ : renderer_host_(renderer_host),
+ temporary_remote_port_route_id_(0),
+ remote_port_id_(0),
+ local_port_route_id_(0),
+ local_port_id_(0),
+ route_id_(0) {}
+ void Create(const std::string& url,
+ const std::string& name,
+ unsigned long long document_id,
+ int render_frame_route_id) {
+ CreateMessagePortPair(renderer_host_,
+ &temporary_remote_port_route_id_,
+ &remote_port_id_,
+ &local_port_route_id_,
+ &local_port_id_);
+ PostCreateWorker(renderer_host_,
+ url,
+ name,
+ document_id,
+ render_frame_route_id,
+ &route_id_);
+ }
+ void SendQueueMessages() {
+ EXPECT_TRUE(renderer_host_->OnMessageReceived(
+ new MessagePortHostMsg_QueueMessages(remote_port_id_)));
+ }
+ void SendPostMessage(std::string data) {
+ const std::vector<int> empty_ids;
+ EXPECT_TRUE(
+ renderer_host_->OnMessageReceived(new MessagePortHostMsg_PostMessage(
+ local_port_id_, base::ASCIIToUTF16(data), empty_ids)));
+ }
+ void SendConnect() {
+ EXPECT_TRUE(
+ renderer_host_->OnMessageReceived(new ViewHostMsg_ForwardToWorker(
+ WorkerMsg_Connect(route_id_, remote_port_id_, MSG_ROUTING_NONE))));
+ }
+ void SendSendQueuedMessages(
+ const std::vector<QueuedMessage>& queued_messages) {
+ EXPECT_TRUE(renderer_host_->OnMessageReceived(
+ new MessagePortHostMsg_SendQueuedMessages(remote_port_id_,
+ queued_messages)));
+ }
+ int temporary_remote_port_route_id() {
+ return temporary_remote_port_route_id_;
+ }
+ int remote_port_id() { return remote_port_id_; }
+ int local_port_route_id() { return local_port_route_id_; }
+ int local_port_id() { return local_port_id_; }
+ int route_id() { return route_id_; }
+
+ private:
+ MockRendererProcessHost* renderer_host_;
+ int temporary_remote_port_route_id_;
+ int remote_port_id_;
+ int local_port_route_id_;
+ int local_port_id_;
+ int route_id_;
+};
+
+void CheckWorkerProcessMsgCreateWorker(
+ MockRendererProcessHost* renderer_host,
+ const std::string& expected_url,
+ const std::string& expected_name,
+ blink::WebContentSecurityPolicyType expected_security_policy_type,
+ int* route_id) {
+ scoped_ptr<IPC::Message> msg(renderer_host->PopMessage());
+ EXPECT_EQ(WorkerProcessMsg_CreateWorker::ID, msg->type());
+ Tuple1<WorkerProcessMsg_CreateWorker_Params> param;
+ EXPECT_TRUE(WorkerProcessMsg_CreateWorker::Read(msg.get(), &param));
+ EXPECT_EQ(GURL(expected_url), param.a.url);
+ EXPECT_EQ(base::ASCIIToUTF16(expected_name), param.a.name);
+ EXPECT_EQ(expected_security_policy_type, param.a.security_policy_type);
+ *route_id = param.a.route_id;
+}
+
+void CheckViewMsgWorkerCreated(MockRendererProcessHost* renderer_host,
+ MockSharedWorkerConnector* connector) {
+ scoped_ptr<IPC::Message> msg(renderer_host->PopMessage());
+ EXPECT_EQ(ViewMsg_WorkerCreated::ID, msg->type());
+ EXPECT_EQ(connector->route_id(), msg->routing_id());
+}
+
+void CheckMessagePortMsgMessagesQueued(MockRendererProcessHost* renderer_host,
+ MockSharedWorkerConnector* connector) {
+ scoped_ptr<IPC::Message> msg(renderer_host->PopMessage());
+ EXPECT_EQ(MessagePortMsg_MessagesQueued::ID, msg->type());
+ EXPECT_EQ(connector->temporary_remote_port_route_id(), msg->routing_id());
+}
+
+void CheckWorkerMsgConnect(MockRendererProcessHost* renderer_host,
+ int expected_msg_route_id,
+ int expected_sent_message_port_id,
+ int* routing_id) {
+ scoped_ptr<IPC::Message> msg(renderer_host->PopMessage());
+ EXPECT_EQ(WorkerMsg_Connect::ID, msg->type());
+ EXPECT_EQ(expected_msg_route_id, msg->routing_id());
+ int port_id;
+ EXPECT_TRUE(WorkerMsg_Connect::Read(msg.get(), &port_id, routing_id));
+ EXPECT_EQ(expected_sent_message_port_id, port_id);
+}
+
+void CheckMessagePortMsgMessage(MockRendererProcessHost* renderer_host,
+ int expected_msg_route_id,
+ std::string expected_data) {
+ scoped_ptr<IPC::Message> msg(renderer_host->PopMessage());
+ EXPECT_EQ(MessagePortMsg_Message::ID, msg->type());
+ EXPECT_EQ(expected_msg_route_id, msg->routing_id());
+ base::string16 data;
+ std::vector<int> sent_message_port_ids;
+ std::vector<int> new_routing_ids;
+ EXPECT_TRUE(MessagePortMsg_Message::Read(
+ msg.get(), &data, &sent_message_port_ids, &new_routing_ids));
+ EXPECT_EQ(base::ASCIIToUTF16(expected_data), data);
+}
+
+void CheckViewMsgWorkerConnected(MockRendererProcessHost* renderer_host,
+ MockSharedWorkerConnector* connector) {
+ scoped_ptr<IPC::Message> msg(renderer_host->PopMessage());
+ EXPECT_EQ(ViewMsg_WorkerConnected::ID, msg->type());
+ EXPECT_EQ(connector->route_id(), msg->routing_id());
+}
+
+} // namespace
+
+class SharedWorkerServiceImplTest : public testing::Test {
+ protected:
+ SharedWorkerServiceImplTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ browser_context_(new TestBrowserContext()),
+ partition_(
+ new WorkerStoragePartition(browser_context_->GetRequestContext(),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL)) {
+ SharedWorkerServiceImpl::GetInstance()
+ ->ChangeUpdateWorkerDependencyFuncForTesting(
+ &SharedWorkerServiceImplTest::MockUpdateWorkerDependency);
+ }
+
+ virtual void SetUp() OVERRIDE {}
+ virtual void TearDown() OVERRIDE {
+ s_update_worker_dependency_call_count_ = 0;
+ s_worker_dependency_added_ids_.clear();
+ s_worker_dependency_removed_ids_.clear();
+ SharedWorkerServiceImpl::GetInstance()->ResetForTesting();
+ }
+ static void MockUpdateWorkerDependency(const std::vector<int>& added_ids,
+ const std::vector<int>& removed_ids) {
+ ++s_update_worker_dependency_call_count_;
+ s_worker_dependency_added_ids_ = added_ids;
+ s_worker_dependency_removed_ids_ = removed_ids;
+ }
+
+ TestBrowserThreadBundle browser_thread_bundle_;
+ scoped_ptr<TestBrowserContext> browser_context_;
+ scoped_ptr<WorkerStoragePartition> partition_;
+ static int s_update_worker_dependency_call_count_;
+ static std::vector<int> s_worker_dependency_added_ids_;
+ static std::vector<int> s_worker_dependency_removed_ids_;
+ DISALLOW_COPY_AND_ASSIGN(SharedWorkerServiceImplTest);
+};
+
+// static
+int SharedWorkerServiceImplTest::s_update_worker_dependency_call_count_;
+std::vector<int> SharedWorkerServiceImplTest::s_worker_dependency_added_ids_;
+std::vector<int> SharedWorkerServiceImplTest::s_worker_dependency_removed_ids_;
+
+TEST_F(SharedWorkerServiceImplTest, BasicTest) {
+ scoped_ptr<MockRendererProcessHost> renderer_host(new MockRendererProcessHost(
+ 100, browser_context_->GetResourceContext(), *partition_.get()));
+ scoped_ptr<MockSharedWorkerConnector> connector(
+ new MockSharedWorkerConnector(renderer_host.get()));
+ int worker_route_id;
+ int worker_msg_port_route_id;
+
+ // SharedWorkerConnector creates two message ports and sends
+ // ViewHostMsg_CreateWorker.
+ connector->Create("http://example.com/w.js", "name", 200, 300);
+ EXPECT_EQ(2U, renderer_host->QueuedMessageCount());
+ // WorkerProcessMsg_CreateWorker should be sent to the renderer in which
+ // SharedWorker will be created.
+ CheckWorkerProcessMsgCreateWorker(renderer_host.get(),
+ "http://example.com/w.js",
+ "name",
+ blink::WebContentSecurityPolicyTypeReport,
+ &worker_route_id);
+ // ViewMsg_WorkerCreated(1) should be sent back to SharedWorkerConnector side.
+ CheckViewMsgWorkerCreated(renderer_host.get(), connector.get());
+
+ // SharedWorkerConnector side sends MessagePortHostMsg_QueueMessages in
+ // WebSharedWorkerProxy::connect.
+ connector->SendQueueMessages();
+ EXPECT_EQ(1U, renderer_host->QueuedMessageCount());
+ // MessagePortMsg_MessagesQueued(2) should be sent back to
+ // SharedWorkerConnector side.
+ CheckMessagePortMsgMessagesQueued(renderer_host.get(), connector.get());
+
+ // When SharedWorkerConnector receives ViewMsg_WorkerCreated(1), it sends
+ // WorkerMsg_Connect wrapped in ViewHostMsg_ForwardToWorker.
+ connector->SendConnect();
+ EXPECT_EQ(1U, renderer_host->QueuedMessageCount());
+ // WorkerMsg_Connect should be sent to SharedWorker side.
+ CheckWorkerMsgConnect(renderer_host.get(),
+ worker_route_id,
+ connector->remote_port_id(),
+ &worker_msg_port_route_id);
+
+ // When SharedWorkerConnector receives MessagePortMsg_MessagesQueued(2), it
+ // sends MessagePortHostMsg_SendQueuedMessages.
+ std::vector<QueuedMessage> empty_messages;
+ connector->SendSendQueuedMessages(empty_messages);
+ EXPECT_EQ(0U, renderer_host->QueuedMessageCount());
+
+ // SharedWorker sends WorkerHostMsg_WorkerScriptLoaded in
+ // EmbeddedSharedWorkerStub::workerScriptLoaded().
+ EXPECT_TRUE(renderer_host->OnMessageReceived(
+ new WorkerHostMsg_WorkerScriptLoaded(worker_route_id)));
+ EXPECT_EQ(0U, renderer_host->QueuedMessageCount());
+
+ // SharedWorker sends WorkerHostMsg_WorkerConnected in
+ // EmbeddedSharedWorkerStub::workerScriptLoaded().
+ EXPECT_TRUE(
+ renderer_host->OnMessageReceived(new WorkerHostMsg_WorkerConnected(
+ connector->remote_port_id(), worker_route_id)));
+ EXPECT_EQ(1U, renderer_host->QueuedMessageCount());
+ // ViewMsg_WorkerConnected should be sent to SharedWorkerConnector side.
+ CheckViewMsgWorkerConnected(renderer_host.get(), connector.get());
+
+ // When SharedWorkerConnector side sends MessagePortHostMsg_PostMessage,
+ // SharedWorker side shuold receive MessagePortMsg_Message.
+ connector->SendPostMessage("test1");
+ EXPECT_EQ(1U, renderer_host->QueuedMessageCount());
+ CheckMessagePortMsgMessage(
+ renderer_host.get(), worker_msg_port_route_id, "test1");
+
+ // When SharedWorker side sends MessagePortHostMsg_PostMessage,
+ // SharedWorkerConnector side shuold receive MessagePortMsg_Message.
+ const std::vector<int> empty_ids;
+ EXPECT_TRUE(renderer_host->OnMessageReceived(
+ new MessagePortHostMsg_PostMessage(connector->remote_port_id(),
+ base::ASCIIToUTF16("test2"),
+ empty_ids)));
+ EXPECT_EQ(1U, renderer_host->QueuedMessageCount());
+ CheckMessagePortMsgMessage(
+ renderer_host.get(), connector->local_port_route_id(), "test2");
+
+ // UpdateWorkerDependency should not be called.
+ EXPECT_EQ(0, s_update_worker_dependency_call_count_);
+}
+
+TEST_F(SharedWorkerServiceImplTest, TwoRendererTest) {
+ // The first renderer host.
+ scoped_ptr<MockRendererProcessHost> renderer_host1(
+ new MockRendererProcessHost(
+ 100, browser_context_->GetResourceContext(), *partition_.get()));
+ scoped_ptr<MockSharedWorkerConnector> connector1(
+ new MockSharedWorkerConnector(renderer_host1.get()));
+ int worker_route_id;
+ int worker_msg_port_route_id1;
+
+ // SharedWorkerConnector creates two message ports and sends
+ // ViewHostMsg_CreateWorker.
+ connector1->Create("http://example.com/w.js", "name", 200, 300);
+ EXPECT_EQ(2U, renderer_host1->QueuedMessageCount());
+ // WorkerProcessMsg_CreateWorker should be sent to the renderer in which
+ // SharedWorker will be created.
+ CheckWorkerProcessMsgCreateWorker(renderer_host1.get(),
+ "http://example.com/w.js",
+ "name",
+ blink::WebContentSecurityPolicyTypeReport,
+ &worker_route_id);
+ // ViewMsg_WorkerCreated(1) should be sent back to SharedWorkerConnector side.
+ CheckViewMsgWorkerCreated(renderer_host1.get(), connector1.get());
+
+ // SharedWorkerConnector side sends MessagePortHostMsg_QueueMessages in
+ // WebSharedWorkerProxy::connect.
+ connector1->SendQueueMessages();
+ EXPECT_EQ(1U, renderer_host1->QueuedMessageCount());
+ // MessagePortMsg_MessagesQueued(2) should be sent back to
+ // SharedWorkerConnector side.
+ CheckMessagePortMsgMessagesQueued(renderer_host1.get(), connector1.get());
+
+ // When SharedWorkerConnector receives ViewMsg_WorkerCreated(1), it sends
+ // WorkerMsg_Connect wrapped in ViewHostMsg_ForwardToWorker.
+ connector1->SendConnect();
+ EXPECT_EQ(1U, renderer_host1->QueuedMessageCount());
+ // WorkerMsg_Connect should be sent to SharedWorker side.
+ CheckWorkerMsgConnect(renderer_host1.get(),
+ worker_route_id,
+ connector1->remote_port_id(),
+ &worker_msg_port_route_id1);
+
+ // When SharedWorkerConnector receives MessagePortMsg_MessagesQueued(2), it
+ // sends MessagePortHostMsg_SendQueuedMessages.
+ std::vector<QueuedMessage> empty_messages;
+ connector1->SendSendQueuedMessages(empty_messages);
+ EXPECT_EQ(0U, renderer_host1->QueuedMessageCount());
+
+ // SharedWorker sends WorkerHostMsg_WorkerScriptLoaded in
+ // EmbeddedSharedWorkerStub::workerScriptLoaded().
+ EXPECT_TRUE(renderer_host1->OnMessageReceived(
+ new WorkerHostMsg_WorkerScriptLoaded(worker_route_id)));
+ EXPECT_EQ(0U, renderer_host1->QueuedMessageCount());
+
+ // SharedWorker sends WorkerHostMsg_WorkerConnected in
+ // EmbeddedSharedWorkerStub::workerScriptLoaded().
+ EXPECT_TRUE(
+ renderer_host1->OnMessageReceived(new WorkerHostMsg_WorkerConnected(
+ connector1->remote_port_id(), worker_route_id)));
+ EXPECT_EQ(1U, renderer_host1->QueuedMessageCount());
+ // ViewMsg_WorkerConnected should be sent to SharedWorkerConnector side.
+ CheckViewMsgWorkerConnected(renderer_host1.get(), connector1.get());
+
+ // When SharedWorkerConnector side sends MessagePortHostMsg_PostMessage,
+ // SharedWorker side shuold receive MessagePortMsg_Message.
+ connector1->SendPostMessage("test1");
+ EXPECT_EQ(1U, renderer_host1->QueuedMessageCount());
+ CheckMessagePortMsgMessage(
+ renderer_host1.get(), worker_msg_port_route_id1, "test1");
+
+ // When SharedWorker side sends MessagePortHostMsg_PostMessage,
+ // SharedWorkerConnector side shuold receive MessagePortMsg_Message.
+ const std::vector<int> empty_ids;
+ EXPECT_TRUE(renderer_host1->OnMessageReceived(
+ new MessagePortHostMsg_PostMessage(connector1->remote_port_id(),
+ base::ASCIIToUTF16("test2"),
+ empty_ids)));
+ EXPECT_EQ(1U, renderer_host1->QueuedMessageCount());
+ CheckMessagePortMsgMessage(
+ renderer_host1.get(), connector1->local_port_route_id(), "test2");
+
+ // The second renderer host.
+ scoped_ptr<MockRendererProcessHost> renderer_host2(
+ new MockRendererProcessHost(
+ 400, browser_context_->GetResourceContext(), *partition_.get()));
+ scoped_ptr<MockSharedWorkerConnector> connector2(
+ new MockSharedWorkerConnector(renderer_host2.get()));
+ int worker_msg_port_route_id2;
+
+ // UpdateWorkerDependency should not be called yet.
+ EXPECT_EQ(0, s_update_worker_dependency_call_count_);
+
+ // SharedWorkerConnector creates two message ports and sends
+ // ViewHostMsg_CreateWorker.
+ connector2->Create("http://example.com/w.js", "name", 500, 600);
+ EXPECT_EQ(1U, renderer_host2->QueuedMessageCount());
+ // ViewMsg_WorkerCreated(3) should be sent back to SharedWorkerConnector side.
+ CheckViewMsgWorkerCreated(renderer_host2.get(), connector2.get());
+
+ // UpdateWorkerDependency should be called.
+ EXPECT_EQ(1, s_update_worker_dependency_call_count_);
+ EXPECT_EQ(1U, s_worker_dependency_added_ids_.size());
+ EXPECT_EQ(100, s_worker_dependency_added_ids_[0]);
+ EXPECT_EQ(0U, s_worker_dependency_removed_ids_.size());
+
+ // SharedWorkerConnector side sends MessagePortHostMsg_QueueMessages in
+ // WebSharedWorkerProxy::connect.
+ connector2->SendQueueMessages();
+ EXPECT_EQ(1U, renderer_host2->QueuedMessageCount());
+ // MessagePortMsg_MessagesQueued(4) should be sent back to
+ // SharedWorkerConnector side.
+ CheckMessagePortMsgMessagesQueued(renderer_host2.get(), connector2.get());
+
+ // When SharedWorkerConnector receives ViewMsg_WorkerCreated(3), it sends
+ // WorkerMsg_Connect wrapped in ViewHostMsg_ForwardToWorker.
+ connector2->SendConnect();
+ EXPECT_EQ(1U, renderer_host1->QueuedMessageCount());
+ // WorkerMsg_Connect should be sent to SharedWorker side.
+ CheckWorkerMsgConnect(renderer_host1.get(),
+ worker_route_id,
+ connector2->remote_port_id(),
+ &worker_msg_port_route_id2);
+
+ // When SharedWorkerConnector receives MessagePortMsg_MessagesQueued(4), it
+ // sends MessagePortHostMsg_SendQueuedMessages.
+ connector2->SendSendQueuedMessages(empty_messages);
+ EXPECT_EQ(0U, renderer_host2->QueuedMessageCount());
+
+ // SharedWorker sends WorkerHostMsg_WorkerConnected in
+ // EmbeddedSharedWorkerStub::OnConnect().
+ EXPECT_TRUE(
+ renderer_host1->OnMessageReceived(new WorkerHostMsg_WorkerConnected(
+ connector2->remote_port_id(), worker_route_id)));
+ EXPECT_EQ(1U, renderer_host2->QueuedMessageCount());
+ // ViewMsg_WorkerConnected should be sent to SharedWorkerConnector side.
+ CheckViewMsgWorkerConnected(renderer_host2.get(), connector2.get());
+
+ // When SharedWorkerConnector side sends MessagePortHostMsg_PostMessage,
+ // SharedWorker side shuold receive MessagePortMsg_Message.
+ connector2->SendPostMessage("test3");
+ EXPECT_EQ(1U, renderer_host1->QueuedMessageCount());
+ CheckMessagePortMsgMessage(
+ renderer_host1.get(), worker_msg_port_route_id2, "test3");
+
+ // When SharedWorker side sends MessagePortHostMsg_PostMessage,
+ // SharedWorkerConnector side shuold receive MessagePortMsg_Message.
+ EXPECT_TRUE(renderer_host1->OnMessageReceived(
+ new MessagePortHostMsg_PostMessage(connector2->remote_port_id(),
+ base::ASCIIToUTF16("test4"),
+ empty_ids)));
+ EXPECT_EQ(1U, renderer_host2->QueuedMessageCount());
+ CheckMessagePortMsgMessage(
+ renderer_host2.get(), connector2->local_port_route_id(), "test4");
+
+ EXPECT_EQ(1, s_update_worker_dependency_call_count_);
+ renderer_host2.reset();
+ // UpdateWorkerDependency should be called.
+ EXPECT_EQ(2, s_update_worker_dependency_call_count_);
+ EXPECT_EQ(0U, s_worker_dependency_added_ids_.size());
+ EXPECT_EQ(1U, s_worker_dependency_removed_ids_.size());
+ EXPECT_EQ(100, s_worker_dependency_removed_ids_[0]);
+}
+
+} // namespace content
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index ab0d5d8..e26d1e4 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -483,6 +483,7 @@
'browser/service_worker/service_worker_storage_unittest.cc',
'browser/service_worker/service_worker_version_unittest.cc',
'browser/shared_worker/shared_worker_instance_unittest.cc',
+ 'browser/shared_worker/shared_worker_service_impl_unittest.cc',
'browser/site_instance_impl_unittest.cc',
'browser/speech/chunked_byte_buffer_unittest.cc',
'browser/speech/endpointer/endpointer_unittest.cc',