blob: b78a6c99e251d1afc1e4385110eb805c086819bc [file] [log] [blame]
// 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 "content/browser/shared_worker/shared_worker_service_impl.h"
#include <stddef.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include "base/atomic_sequence_num.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "content/browser/shared_worker/shared_worker_connector_impl.h"
#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/browser/site_instance_impl.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_utils.h"
#include "content/test/test_render_frame_host.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/common/message_port/message_port_channel.h"
using blink::MessagePortChannel;
namespace content {
class SharedWorkerServiceImplTest : public RenderViewHostImplTestHarness {
public:
mojom::SharedWorkerConnectorPtr MakeSharedWorkerConnector(
RenderProcessHost* process_host,
int frame_id) {
mojom::SharedWorkerConnectorPtr connector;
SharedWorkerConnectorImpl::CreateInternal(
process_host->GetID(), frame_id,
process_host->GetBrowserContext()->GetResourceContext(), *partition_,
mojo::MakeRequest(&connector));
return connector;
}
static bool CheckReceivedFactoryRequest(
mojom::SharedWorkerFactoryRequest* request) {
if (s_factory_request_received_.empty())
return false;
*request = std::move(s_factory_request_received_.front());
s_factory_request_received_.pop();
return true;
}
static bool CheckNotReceivedFactoryRequest() {
return s_factory_request_received_.empty();
}
static void BindSharedWorkerFactory(mojo::ScopedMessagePipeHandle handle) {
s_factory_request_received_.push(
mojom::SharedWorkerFactoryRequest(std::move(handle)));
}
std::unique_ptr<TestWebContents> CreateWebContents(const GURL& url) {
std::unique_ptr<TestWebContents> web_contents(TestWebContents::Create(
browser_context_.get(),
SiteInstanceImpl::Create(browser_context_.get())));
web_contents->NavigateAndCommit(url);
return web_contents;
}
protected:
SharedWorkerServiceImplTest()
: browser_context_(new TestBrowserContext()),
partition_(new WorkerStoragePartition(
BrowserContext::GetDefaultStoragePartition(browser_context_.get())
->GetURLRequestContext(),
nullptr /* media_url_request_context */,
nullptr /* appcache_service */,
nullptr /* quota_manager */,
nullptr /* filesystem_context */,
nullptr /* database_tracker */,
nullptr /* indexed_db_context */,
nullptr /* service_worker_context */)) {}
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
render_process_host_factory_ =
std::make_unique<MockRenderProcessHostFactory>();
RenderProcessHostImpl::set_render_process_host_factory(
render_process_host_factory_.get());
}
void TearDown() override {
static_cast<SharedWorkerServiceImpl*>(SharedWorkerService::GetInstance())
->ResetForTesting();
browser_context_.reset();
RenderViewHostImplTestHarness::TearDown();
}
std::unique_ptr<TestBrowserContext> browser_context_;
std::unique_ptr<WorkerStoragePartition> partition_;
static std::queue<mojom::SharedWorkerFactoryRequest>
s_factory_request_received_;
std::unique_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
private:
DISALLOW_COPY_AND_ASSIGN(SharedWorkerServiceImplTest);
};
// static
std::queue<mojom::SharedWorkerFactoryRequest>
SharedWorkerServiceImplTest::s_factory_request_received_;
namespace {
template <typename T>
static bool CheckEquality(const T& expected, const T& actual) {
EXPECT_EQ(expected, actual);
return expected == actual;
}
std::vector<uint8_t> StringPieceToVector(base::StringPiece s) {
return std::vector<uint8_t>(s.begin(), s.end());
}
void BlockingReadFromMessagePort(MessagePortChannel port,
std::vector<uint8_t>* message) {
base::RunLoop run_loop;
port.SetCallback(run_loop.QuitClosure(), base::ThreadTaskRunnerHandle::Get());
run_loop.Run();
std::vector<MessagePortChannel> should_be_empty;
EXPECT_TRUE(port.GetMessage(message, &should_be_empty));
EXPECT_TRUE(should_be_empty.empty());
}
class MockSharedWorker : public mojom::SharedWorker {
public:
explicit MockSharedWorker(mojom::SharedWorkerRequest request)
: binding_(this, std::move(request)) {}
bool CheckReceivedConnect(int* connection_request_id,
MessagePortChannel* port) {
if (connect_received_.empty())
return false;
if (connection_request_id)
*connection_request_id = connect_received_.front().first;
if (port)
*port = connect_received_.front().second;
connect_received_.pop();
return true;
}
bool CheckNotReceivedConnect() { return connect_received_.empty(); }
bool CheckReceivedTerminate() {
if (!terminate_received_)
return false;
terminate_received_ = false;
return true;
}
private:
// mojom::SharedWorker methods:
void Connect(int connection_request_id,
mojo::ScopedMessagePipeHandle port) override {
connect_received_.emplace(connection_request_id,
MessagePortChannel(std::move(port)));
}
void Terminate() override {
// Allow duplicate events.
terminate_received_ = true;
}
mojo::Binding<mojom::SharedWorker> binding_;
std::queue<std::pair<int, MessagePortChannel>> connect_received_;
bool terminate_received_ = false;
};
class MockSharedWorkerFactory : public mojom::SharedWorkerFactory {
public:
explicit MockSharedWorkerFactory(mojom::SharedWorkerFactoryRequest request)
: binding_(this, std::move(request)) {}
bool CheckReceivedCreateSharedWorker(
const std::string& expected_url,
const std::string& expected_name,
blink::WebContentSecurityPolicyType expected_content_security_policy_type,
mojom::SharedWorkerHostPtr* host,
mojom::SharedWorkerRequest* request) {
std::unique_ptr<CreateParams> create_params = std::move(create_params_);
if (!create_params)
return false;
if (!CheckEquality(GURL(expected_url), create_params->info->url))
return false;
if (!CheckEquality(expected_name, create_params->info->name))
return false;
if (!CheckEquality(expected_content_security_policy_type,
create_params->info->content_security_policy_type))
return false;
if (!create_params->interface_provider)
return false;
*host = std::move(create_params->host);
*request = std::move(create_params->request);
return true;
}
private:
// mojom::SharedWorkerFactory methods:
void CreateSharedWorker(
mojom::SharedWorkerInfoPtr info,
bool pause_on_start,
const base::UnguessableToken& devtools_worker_token,
int32_t route_id,
blink::mojom::WorkerContentSettingsProxyPtr content_settings,
mojom::SharedWorkerHostPtr host,
mojom::SharedWorkerRequest request,
service_manager::mojom::InterfaceProviderPtr interface_provider)
override {
CHECK(!create_params_);
create_params_ = std::make_unique<CreateParams>();
create_params_->info = std::move(info);
create_params_->pause_on_start = pause_on_start;
create_params_->route_id = route_id;
create_params_->content_settings = std::move(content_settings);
create_params_->host = std::move(host);
create_params_->request = std::move(request);
create_params_->interface_provider = std::move(interface_provider);
}
struct CreateParams {
mojom::SharedWorkerInfoPtr info;
bool pause_on_start;
int32_t route_id;
blink::mojom::WorkerContentSettingsProxyPtr content_settings;
mojom::SharedWorkerHostPtr host;
mojom::SharedWorkerRequest request;
service_manager::mojom::InterfaceProviderPtr interface_provider;
};
mojo::Binding<mojom::SharedWorkerFactory> binding_;
std::unique_ptr<CreateParams> create_params_;
};
class MockSharedWorkerClient : public mojom::SharedWorkerClient {
public:
MockSharedWorkerClient() : binding_(this) {}
void Bind(mojom::SharedWorkerClientRequest request) {
binding_.Bind(std::move(request));
}
void Close() { binding_.Close(); }
bool CheckReceivedOnCreated() {
if (!on_created_received_)
return false;
on_created_received_ = false;
return true;
}
bool CheckReceivedOnConnected(
std::set<blink::mojom::WebFeature> expected_used_features) {
if (!on_connected_received_)
return false;
on_connected_received_ = false;
if (!CheckEquality(expected_used_features, on_connected_features_))
return false;
return true;
}
bool CheckReceivedOnFeatureUsed(blink::mojom::WebFeature expected_feature) {
if (!on_feature_used_received_)
return false;
on_feature_used_received_ = false;
if (!CheckEquality(expected_feature, on_feature_used_feature_))
return false;
return true;
}
bool CheckNotReceivedOnFeatureUsed() { return !on_feature_used_received_; }
private:
// mojom::SharedWorkerClient methods:
void OnCreated(blink::mojom::SharedWorkerCreationContextType
creation_context_type) override {
CHECK(!on_created_received_);
on_created_received_ = true;
}
void OnConnected(
const std::vector<blink::mojom::WebFeature>& features_used) override {
CHECK(!on_connected_received_);
on_connected_received_ = true;
for (auto feature : features_used)
on_connected_features_.insert(feature);
}
void OnScriptLoadFailed() override { NOTREACHED(); }
void OnFeatureUsed(blink::mojom::WebFeature feature) override {
CHECK(!on_feature_used_received_);
on_feature_used_received_ = true;
on_feature_used_feature_ = feature;
}
mojo::Binding<mojom::SharedWorkerClient> binding_;
bool on_created_received_ = false;
bool on_connected_received_ = false;
std::set<blink::mojom::WebFeature> on_connected_features_;
bool on_feature_used_received_ = false;
blink::mojom::WebFeature on_feature_used_feature_ =
blink::mojom::WebFeature();
};
void ConnectToSharedWorker(mojom::SharedWorkerConnectorPtr connector,
const std::string& url,
const std::string& name,
MockSharedWorkerClient* client,
MessagePortChannel* local_port) {
mojom::SharedWorkerInfoPtr info(
mojom::SharedWorkerInfo::New(GURL(url), name, std::string(),
blink::kWebContentSecurityPolicyTypeReport,
blink::kWebAddressSpacePublic));
mojo::MessagePipe message_pipe;
*local_port = MessagePortChannel(std::move(message_pipe.handle0));
mojom::SharedWorkerClientPtr client_proxy;
client->Bind(mojo::MakeRequest(&client_proxy));
connector->Connect(std::move(info), std::move(client_proxy),
blink::mojom::SharedWorkerCreationContextType::kSecure,
std::move(message_pipe.handle1));
}
} // namespace
TEST_F(SharedWorkerServiceImplTest, BasicTest) {
std::unique_ptr<TestWebContents> web_contents =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host = web_contents->GetMainFrame();
MockRenderProcessHost* renderer_host = render_frame_host->GetProcess();
renderer_host->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
MockSharedWorkerClient client;
MessagePortChannel local_port;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host, render_frame_host->GetRoutingID()),
"http://example.com/w.js", "name", &client,
&local_port);
RunAllPendingInMessageLoop();
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host;
mojom::SharedWorkerRequest worker_request;
EXPECT_TRUE(factory.CheckReceivedCreateSharedWorker(
"http://example.com/w.js", "name",
blink::kWebContentSecurityPolicyTypeReport, &worker_host,
&worker_request));
MockSharedWorker worker(std::move(worker_request));
RunAllPendingInMessageLoop();
int connection_request_id;
MessagePortChannel port;
EXPECT_TRUE(worker.CheckReceivedConnect(&connection_request_id, &port));
client.CheckReceivedOnCreated();
// Simulate events the shared worker would send.
worker_host->OnReadyForInspection();
worker_host->OnScriptLoaded();
worker_host->OnConnected(connection_request_id);
RunAllPendingInMessageLoop();
EXPECT_TRUE(
client.CheckReceivedOnConnected(std::set<blink::mojom::WebFeature>()));
// Verify that |port| corresponds to |connector->local_port()|.
std::vector<uint8_t> expected_message(StringPieceToVector("test1"));
local_port.PostMessage(expected_message.data(), expected_message.size(),
std::vector<MessagePortChannel>());
std::vector<uint8_t> received_message;
BlockingReadFromMessagePort(port, &received_message);
EXPECT_EQ(expected_message, received_message);
// Send feature from shared worker to host.
auto feature1 = static_cast<blink::mojom::WebFeature>(124);
worker_host->OnFeatureUsed(feature1);
RunAllPendingInMessageLoop();
EXPECT_TRUE(client.CheckReceivedOnFeatureUsed(feature1));
// A message should be sent only one time per feature.
worker_host->OnFeatureUsed(feature1);
RunAllPendingInMessageLoop();
EXPECT_TRUE(client.CheckNotReceivedOnFeatureUsed());
// Send another feature.
auto feature2 = static_cast<blink::mojom::WebFeature>(901);
worker_host->OnFeatureUsed(feature2);
RunAllPendingInMessageLoop();
EXPECT_TRUE(client.CheckReceivedOnFeatureUsed(feature2));
}
TEST_F(SharedWorkerServiceImplTest, TwoRendererTest) {
// The first renderer host.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
"http://example.com/w.js", "name", &client0,
&local_port0);
RunAllPendingInMessageLoop();
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host;
mojom::SharedWorkerRequest worker_request;
EXPECT_TRUE(factory.CheckReceivedCreateSharedWorker(
"http://example.com/w.js", "name",
blink::kWebContentSecurityPolicyTypeReport, &worker_host,
&worker_request));
MockSharedWorker worker(std::move(worker_request));
RunAllPendingInMessageLoop();
int connection_request_id0;
MessagePortChannel port0;
EXPECT_TRUE(worker.CheckReceivedConnect(&connection_request_id0, &port0));
client0.CheckReceivedOnCreated();
// Simulate events the shared worker would send.
worker_host->OnReadyForInspection();
worker_host->OnScriptLoaded();
worker_host->OnConnected(connection_request_id0);
RunAllPendingInMessageLoop();
EXPECT_TRUE(
client0.CheckReceivedOnConnected(std::set<blink::mojom::WebFeature>()));
// Verify that |port0| corresponds to |connector0->local_port()|.
std::vector<uint8_t> expected_message0(StringPieceToVector("test1"));
local_port0.PostMessage(expected_message0.data(), expected_message0.size(),
std::vector<MessagePortChannel>());
std::vector<uint8_t> received_message0;
BlockingReadFromMessagePort(port0, &received_message0);
EXPECT_EQ(expected_message0, received_message0);
auto feature1 = static_cast<blink::mojom::WebFeature>(124);
worker_host->OnFeatureUsed(feature1);
RunAllPendingInMessageLoop();
EXPECT_TRUE(client0.CheckReceivedOnFeatureUsed(feature1));
auto feature2 = static_cast<blink::mojom::WebFeature>(901);
worker_host->OnFeatureUsed(feature2);
RunAllPendingInMessageLoop();
EXPECT_TRUE(client0.CheckReceivedOnFeatureUsed(feature2));
// Only a single worker instance in process 0.
EXPECT_EQ(1u, renderer_host0->GetKeepAliveRefCount());
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
"http://example.com/w.js", "name", &client1,
&local_port1);
RunAllPendingInMessageLoop();
// Should not have tried to create a new shared worker.
EXPECT_TRUE(CheckNotReceivedFactoryRequest());
int connection_request_id1;
MessagePortChannel port1;
EXPECT_TRUE(worker.CheckReceivedConnect(&connection_request_id1, &port1));
client1.CheckReceivedOnCreated();
// Only a single worker instance in process 0.
EXPECT_EQ(1u, renderer_host0->GetKeepAliveRefCount());
EXPECT_EQ(0u, renderer_host1->GetKeepAliveRefCount());
worker_host->OnConnected(connection_request_id1);
RunAllPendingInMessageLoop();
EXPECT_TRUE(client1.CheckReceivedOnConnected({feature1, feature2}));
// Verify that |worker_msg_port2| corresponds to |connector1->local_port()|.
std::vector<uint8_t> expected_message1(StringPieceToVector("test2"));
local_port1.PostMessage(expected_message1.data(), expected_message1.size(),
std::vector<MessagePortChannel>());
std::vector<uint8_t> received_message1;
BlockingReadFromMessagePort(port1, &received_message1);
EXPECT_EQ(expected_message1, received_message1);
worker_host->OnFeatureUsed(feature1);
RunAllPendingInMessageLoop();
EXPECT_TRUE(client0.CheckNotReceivedOnFeatureUsed());
EXPECT_TRUE(client1.CheckNotReceivedOnFeatureUsed());
auto feature3 = static_cast<blink::mojom::WebFeature>(1019);
worker_host->OnFeatureUsed(feature3);
RunAllPendingInMessageLoop();
EXPECT_TRUE(client0.CheckReceivedOnFeatureUsed(feature3));
EXPECT_TRUE(client1.CheckReceivedOnFeatureUsed(feature3));
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase) {
const char kURL[] = "http://example.com/w.js";
const char kName[] = "name";
// The first renderer host.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// First client, creates worker.
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kURL, kName, &client0, &local_port0);
RunAllPendingInMessageLoop();
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host;
mojom::SharedWorkerRequest worker_request;
EXPECT_TRUE(factory.CheckReceivedCreateSharedWorker(
kURL, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host,
&worker_request));
MockSharedWorker worker(std::move(worker_request));
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
client0.CheckReceivedOnCreated();
// Second client, same worker.
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kURL, kName, &client1, &local_port1);
RunAllPendingInMessageLoop();
EXPECT_TRUE(CheckNotReceivedFactoryRequest());
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
client1.CheckReceivedOnCreated();
// Cleanup
client0.Close();
client1.Close();
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase_URLMismatch) {
const char kURL0[] = "http://example.com/w0.js";
const char kURL1[] = "http://example.com/w1.js";
const char kName[] = "name";
// The first renderer host.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// First client, creates worker.
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kURL0, kName, &client0, &local_port0);
RunAllPendingInMessageLoop();
mojom::SharedWorkerFactoryRequest factory_request0;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request0));
MockSharedWorkerFactory factory0(std::move(factory_request0));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host0;
mojom::SharedWorkerRequest worker_request0;
EXPECT_TRUE(factory0.CheckReceivedCreateSharedWorker(
kURL0, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host0,
&worker_request0));
MockSharedWorker worker0(std::move(worker_request0));
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
client0.CheckReceivedOnCreated();
// Second client, creates worker.
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kURL1, kName, &client1, &local_port1);
RunAllPendingInMessageLoop();
mojom::SharedWorkerFactoryRequest factory_request1;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request1));
MockSharedWorkerFactory factory1(std::move(factory_request1));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host1;
mojom::SharedWorkerRequest worker_request1;
EXPECT_TRUE(factory1.CheckReceivedCreateSharedWorker(
kURL1, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host1,
&worker_request1));
MockSharedWorker worker1(std::move(worker_request1));
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
client1.CheckReceivedOnCreated();
// Cleanup
client0.Close();
client1.Close();
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker0.CheckReceivedTerminate());
EXPECT_TRUE(worker1.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase_NameMismatch) {
const char kURL[] = "http://example.com/w.js";
const char kName0[] = "name0";
const char kName1[] = "name1";
// The first renderer host.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// First client, creates worker.
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kURL, kName0, &client0, &local_port0);
RunAllPendingInMessageLoop();
mojom::SharedWorkerFactoryRequest factory_request0;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request0));
MockSharedWorkerFactory factory0(std::move(factory_request0));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host0;
mojom::SharedWorkerRequest worker_request0;
EXPECT_TRUE(factory0.CheckReceivedCreateSharedWorker(
kURL, kName0, blink::kWebContentSecurityPolicyTypeReport, &worker_host0,
&worker_request0));
MockSharedWorker worker0(std::move(worker_request0));
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
client0.CheckReceivedOnCreated();
// Second client, creates worker.
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kURL, kName1, &client1, &local_port1);
RunAllPendingInMessageLoop();
mojom::SharedWorkerFactoryRequest factory_request1;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request1));
MockSharedWorkerFactory factory1(std::move(factory_request1));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host1;
mojom::SharedWorkerRequest worker_request1;
EXPECT_TRUE(factory1.CheckReceivedCreateSharedWorker(
kURL, kName1, blink::kWebContentSecurityPolicyTypeReport, &worker_host1,
&worker_request1));
MockSharedWorker worker1(std::move(worker_request1));
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
client1.CheckReceivedOnCreated();
// Cleanup
client0.Close();
client1.Close();
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker0.CheckReceivedTerminate());
EXPECT_TRUE(worker1.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase) {
const char kURL[] = "http://example.com/w.js";
const char kName[] = "name";
// The first renderer host.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// First client and second client are created before the worker starts.
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kURL, kName, &client0, &local_port0);
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kURL, kName, &client1, &local_port1);
RunAllPendingInMessageLoop();
// Check that the worker was created.
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host;
mojom::SharedWorkerRequest worker_request;
EXPECT_TRUE(factory.CheckReceivedCreateSharedWorker(
kURL, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host,
&worker_request));
MockSharedWorker worker(std::move(worker_request));
RunAllPendingInMessageLoop();
// Check that the worker received two connections.
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
client0.CheckReceivedOnCreated();
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
client1.CheckReceivedOnCreated();
// Cleanup
client0.Close();
client1.Close();
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_URLMismatch) {
const char kURL0[] = "http://example.com/w0.js";
const char kURL1[] = "http://example.com/w1.js";
const char kName[] = "name";
// The first renderer host.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// First client and second client are created before the workers start.
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kURL0, kName, &client0, &local_port0);
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kURL1, kName, &client1, &local_port1);
RunAllPendingInMessageLoop();
// Check that both workers were created.
mojom::SharedWorkerFactoryRequest factory_request0;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request0));
MockSharedWorkerFactory factory0(std::move(factory_request0));
mojom::SharedWorkerFactoryRequest factory_request1;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request1));
MockSharedWorkerFactory factory1(std::move(factory_request1));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host0;
mojom::SharedWorkerRequest worker_request0;
EXPECT_TRUE(factory0.CheckReceivedCreateSharedWorker(
kURL0, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host0,
&worker_request0));
MockSharedWorker worker0(std::move(worker_request0));
mojom::SharedWorkerHostPtr worker_host1;
mojom::SharedWorkerRequest worker_request1;
EXPECT_TRUE(factory1.CheckReceivedCreateSharedWorker(
kURL1, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host1,
&worker_request1));
MockSharedWorker worker1(std::move(worker_request1));
RunAllPendingInMessageLoop();
// Check that the workers each received a connection.
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(worker0.CheckNotReceivedConnect());
client0.CheckReceivedOnCreated();
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(worker1.CheckNotReceivedConnect());
client1.CheckReceivedOnCreated();
// Cleanup
client0.Close();
client1.Close();
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker0.CheckReceivedTerminate());
EXPECT_TRUE(worker1.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_NameMismatch) {
const char kURL[] = "http://example.com/w.js";
const char kName0[] = "name0";
const char kName1[] = "name1";
// The first renderer host.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// The second renderer host.
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
// First client and second client are created before the workers start.
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kURL, kName0, &client0, &local_port0);
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kURL, kName1, &client1, &local_port1);
RunAllPendingInMessageLoop();
// Check that both workers were created.
mojom::SharedWorkerFactoryRequest factory_request0;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request0));
MockSharedWorkerFactory factory0(std::move(factory_request0));
mojom::SharedWorkerFactoryRequest factory_request1;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request1));
MockSharedWorkerFactory factory1(std::move(factory_request1));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host0;
mojom::SharedWorkerRequest worker_request0;
EXPECT_TRUE(factory0.CheckReceivedCreateSharedWorker(
kURL, kName0, blink::kWebContentSecurityPolicyTypeReport, &worker_host0,
&worker_request0));
MockSharedWorker worker0(std::move(worker_request0));
mojom::SharedWorkerHostPtr worker_host1;
mojom::SharedWorkerRequest worker_request1;
EXPECT_TRUE(factory1.CheckReceivedCreateSharedWorker(
kURL, kName1, blink::kWebContentSecurityPolicyTypeReport, &worker_host1,
&worker_request1));
MockSharedWorker worker1(std::move(worker_request1));
RunAllPendingInMessageLoop();
// Check that the workers each received a connection.
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(worker0.CheckNotReceivedConnect());
client0.CheckReceivedOnCreated();
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(worker1.CheckNotReceivedConnect());
client1.CheckReceivedOnCreated();
// Cleanup
client0.Close();
client1.Close();
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker0.CheckReceivedTerminate());
EXPECT_TRUE(worker1.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest) {
const char kURL[] = "http://example.com/w.js";
const char kName[] = "name";
// Create three renderer hosts.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
std::unique_ptr<TestWebContents> web_contents2 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host2 = web_contents2->GetMainFrame();
MockRenderProcessHost* renderer_host2 = render_frame_host2->GetProcess();
renderer_host2->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kURL, kName, &client0, &local_port0);
RunAllPendingInMessageLoop();
// Starts a worker.
mojom::SharedWorkerFactoryRequest factory_request0;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request0));
MockSharedWorkerFactory factory0(std::move(factory_request0));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host0;
mojom::SharedWorkerRequest worker_request0;
EXPECT_TRUE(factory0.CheckReceivedCreateSharedWorker(
kURL, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host0,
&worker_request0));
MockSharedWorker worker0(std::move(worker_request0));
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
client0.CheckReceivedOnCreated();
// Kill this process, which should make worker0 unavailable.
web_contents0.reset();
renderer_host0->FastShutdownIfPossible(0, true);
ASSERT_TRUE(renderer_host0->FastShutdownStarted());
// Start a new client, attemping to connect to the same worker.
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kURL, kName, &client1, &local_port1);
RunAllPendingInMessageLoop();
// The previous worker is unavailable, so a new worker is created.
mojom::SharedWorkerFactoryRequest factory_request1;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request1));
MockSharedWorkerFactory factory1(std::move(factory_request1));
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host1;
mojom::SharedWorkerRequest worker_request1;
EXPECT_TRUE(factory1.CheckReceivedCreateSharedWorker(
kURL, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host1,
&worker_request1));
MockSharedWorker worker1(std::move(worker_request1));
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker0.CheckNotReceivedConnect());
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
client1.CheckReceivedOnCreated();
// Start another client to confirm that it can connect to the same worker.
MockSharedWorkerClient client2;
MessagePortChannel local_port2;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host2, render_frame_host2->GetRoutingID()),
kURL, kName, &client2, &local_port2);
RunAllPendingInMessageLoop();
EXPECT_TRUE(CheckNotReceivedFactoryRequest());
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
client2.CheckReceivedOnCreated();
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest2) {
const char kURL[] = "http://example.com/w.js";
const char kName[] = "name";
// Create three renderer hosts.
std::unique_ptr<TestWebContents> web_contents0 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host0 = web_contents0->GetMainFrame();
MockRenderProcessHost* renderer_host0 = render_frame_host0->GetProcess();
renderer_host0->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
std::unique_ptr<TestWebContents> web_contents1 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host1 = web_contents1->GetMainFrame();
MockRenderProcessHost* renderer_host1 = render_frame_host1->GetProcess();
renderer_host1->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
std::unique_ptr<TestWebContents> web_contents2 =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host2 = web_contents2->GetMainFrame();
MockRenderProcessHost* renderer_host2 = render_frame_host2->GetProcess();
renderer_host2->OverrideBinderForTesting(
mojom::SharedWorkerFactory::Name_,
base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kURL, kName, &client0, &local_port0);
// Kill this process, which should make worker0 unavailable.
renderer_host0->FastShutdownIfPossible(0, true);
// Start a new client, attemping to connect to the same worker.
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kURL, kName, &client1, &local_port1);
RunAllPendingInMessageLoop();
// The previous worker is unavailable, so a new worker is created.
mojom::SharedWorkerFactoryRequest factory_request1;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request1));
MockSharedWorkerFactory factory1(std::move(factory_request1));
EXPECT_TRUE(CheckNotReceivedFactoryRequest());
RunAllPendingInMessageLoop();
mojom::SharedWorkerHostPtr worker_host1;
mojom::SharedWorkerRequest worker_request1;
EXPECT_TRUE(factory1.CheckReceivedCreateSharedWorker(
kURL, kName, blink::kWebContentSecurityPolicyTypeReport, &worker_host1,
&worker_request1));
MockSharedWorker worker1(std::move(worker_request1));
RunAllPendingInMessageLoop();
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
client1.CheckReceivedOnCreated();
// Start another client to confirm that it can connect to the same worker.
MockSharedWorkerClient client2;
MessagePortChannel local_port2;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host2, render_frame_host2->GetRoutingID()),
kURL, kName, &client2, &local_port2);
RunAllPendingInMessageLoop();
EXPECT_TRUE(CheckNotReceivedFactoryRequest());
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
client2.CheckReceivedOnCreated();
}
} // namespace content