blob: 49aa62c34d91a1a4b7900b3c138d742f2ae6397e [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 <memory>
#include <queue>
#include <set>
#include <string>
#include "base/macros.h"
#include "base/run_loop.h"
#include "content/browser/shared_worker/mock_shared_worker.h"
#include "content/browser/shared_worker/shared_worker_connector_impl.h"
#include "content/browser/site_instance_impl.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/not_implemented_network_url_loader_factory.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 "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/messaging/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::Create(process_host->GetID(), frame_id,
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()) {}
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
render_process_host_factory_ =
std::make_unique<MockRenderProcessHostFactory>();
RenderProcessHostImpl::set_render_process_host_factory_for_testing(
render_process_host_factory_.get());
url_loader_factory_ =
std::make_unique<NotImplementedNetworkURLLoaderFactory>();
}
void TearDown() override {
browser_context_.reset();
RenderViewHostImplTestHarness::TearDown();
}
std::unique_ptr<TestBrowserContext> browser_context_;
static std::queue<mojom::SharedWorkerFactoryRequest>
s_factory_request_received_;
std::unique_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
std::unique_ptr<NotImplementedNetworkURLLoaderFactory> url_loader_factory_;
private:
DISALLOW_COPY_AND_ASSIGN(SharedWorkerServiceImplTest);
};
// static
std::queue<mojom::SharedWorkerFactoryRequest>
SharedWorkerServiceImplTest::s_factory_request_received_;
namespace {
void ConnectToSharedWorker(mojom::SharedWorkerConnectorPtr connector,
const GURL& url,
const std::string& name,
MockSharedWorkerClient* client,
MessagePortChannel* local_port) {
mojom::SharedWorkerInfoPtr info(mojom::SharedWorkerInfo::New(
url, name, std::string(), blink::kWebContentSecurityPolicyTypeReport,
blink::mojom::IPAddressSpace::kPublic));
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), nullptr);
}
} // 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));
renderer_host->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client;
MessagePortChannel local_port;
const GURL kUrl("http://example.com/w.js");
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host, render_frame_host->GetRoutingID()),
kUrl, "name", &client, &local_port);
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerHostPtr worker_host;
mojom::SharedWorkerRequest worker_request;
EXPECT_TRUE(factory.CheckReceivedCreateSharedWorker(
kUrl, "name", blink::kWebContentSecurityPolicyTypeReport, &worker_host,
&worker_request));
MockSharedWorker worker(std::move(worker_request));
base::RunLoop().RunUntilIdle();
int connection_request_id;
MessagePortChannel port;
EXPECT_TRUE(worker.CheckReceivedConnect(&connection_request_id, &port));
EXPECT_TRUE(client.CheckReceivedOnCreated());
// Simulate events the shared worker would send.
worker_host->OnReadyForInspection();
worker_host->OnScriptLoaded();
worker_host->OnConnected(connection_request_id);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(
client.CheckReceivedOnConnected(std::set<blink::mojom::WebFeature>()));
// Verify that |port| corresponds to |connector->local_port()|.
std::string expected_message("test1");
EXPECT_TRUE(mojo::test::WriteTextMessage(local_port.GetHandle().get(),
expected_message));
std::string received_message;
EXPECT_TRUE(
mojo::test::ReadTextMessage(port.GetHandle().get(), &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);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(client.CheckReceivedOnFeatureUsed(feature1));
// A message should be sent only one time per feature.
worker_host->OnFeatureUsed(feature1);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(client.CheckNotReceivedOnFeatureUsed());
// Send another feature.
auto feature2 = static_cast<blink::mojom::WebFeature>(901);
worker_host->OnFeatureUsed(feature2);
base::RunLoop().RunUntilIdle();
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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
const GURL kUrl("http://example.com/w.js");
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kUrl, "name", &client0, &local_port0);
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerHostPtr worker_host;
mojom::SharedWorkerRequest worker_request;
EXPECT_TRUE(factory.CheckReceivedCreateSharedWorker(
kUrl, "name", blink::kWebContentSecurityPolicyTypeReport, &worker_host,
&worker_request));
MockSharedWorker worker(std::move(worker_request));
base::RunLoop().RunUntilIdle();
int connection_request_id0;
MessagePortChannel port0;
EXPECT_TRUE(worker.CheckReceivedConnect(&connection_request_id0, &port0));
EXPECT_TRUE(client0.CheckReceivedOnCreated());
// Simulate events the shared worker would send.
worker_host->OnReadyForInspection();
worker_host->OnScriptLoaded();
worker_host->OnConnected(connection_request_id0);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(
client0.CheckReceivedOnConnected(std::set<blink::mojom::WebFeature>()));
// Verify that |port0| corresponds to |connector0->local_port()|.
std::string expected_message0("test1");
EXPECT_TRUE(mojo::test::WriteTextMessage(local_port0.GetHandle().get(),
expected_message0));
std::string received_message0;
EXPECT_TRUE(
mojo::test::ReadTextMessage(port0.GetHandle().get(), &received_message0));
EXPECT_EQ(expected_message0, received_message0);
auto feature1 = static_cast<blink::mojom::WebFeature>(124);
worker_host->OnFeatureUsed(feature1);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(client0.CheckReceivedOnFeatureUsed(feature1));
auto feature2 = static_cast<blink::mojom::WebFeature>(901);
worker_host->OnFeatureUsed(feature2);
base::RunLoop().RunUntilIdle();
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));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kUrl, "name", &client1, &local_port1);
base::RunLoop().RunUntilIdle();
// 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));
EXPECT_TRUE(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);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(client1.CheckReceivedOnConnected({feature1, feature2}));
// Verify that |worker_msg_port2| corresponds to |connector1->local_port()|.
std::string expected_message1("test2");
EXPECT_TRUE(mojo::test::WriteTextMessage(local_port1.GetHandle().get(),
expected_message1));
std::string received_message1;
EXPECT_TRUE(
mojo::test::ReadTextMessage(port1.GetHandle().get(), &received_message1));
EXPECT_EQ(expected_message1, received_message1);
worker_host->OnFeatureUsed(feature1);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(client0.CheckNotReceivedOnFeatureUsed());
EXPECT_TRUE(client1.CheckNotReceivedOnFeatureUsed());
auto feature3 = static_cast<blink::mojom::WebFeature>(1019);
worker_host->OnFeatureUsed(feature3);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(client0.CheckReceivedOnFeatureUsed(feature3));
EXPECT_TRUE(client1.CheckReceivedOnFeatureUsed(feature3));
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase) {
const GURL 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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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);
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client0.CheckReceivedOnCreated());
// Second client, same worker.
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kUrl, kName, &client1, &local_port1);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(CheckNotReceivedFactoryRequest());
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client1.CheckReceivedOnCreated());
// Cleanup
client0.Close();
client1.Close();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase_URLMismatch) {
const GURL kUrl0("http://example.com/w0.js");
const GURL 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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// First client, creates worker.
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kUrl0, kName, &client0, &local_port0);
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerFactoryRequest factory_request0;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request0));
MockSharedWorkerFactory factory0(std::move(factory_request0));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client0.CheckReceivedOnCreated());
// Second client, creates worker.
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kUrl1, kName, &client1, &local_port1);
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerFactoryRequest factory_request1;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request1));
MockSharedWorkerFactory factory1(std::move(factory_request1));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client1.CheckReceivedOnCreated());
// Cleanup
client0.Close();
client1.Close();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker0.CheckReceivedTerminate());
EXPECT_TRUE(worker1.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_NormalCase_NameMismatch) {
const GURL 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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// First client, creates worker.
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kUrl, kName0, &client0, &local_port0);
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerFactoryRequest factory_request0;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request0));
MockSharedWorkerFactory factory0(std::move(factory_request0));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client0.CheckReceivedOnCreated());
// Second client, creates worker.
MockSharedWorkerClient client1;
MessagePortChannel local_port1;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host1, render_frame_host1->GetRoutingID()),
kUrl, kName1, &client1, &local_port1);
base::RunLoop().RunUntilIdle();
mojom::SharedWorkerFactoryRequest factory_request1;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request1));
MockSharedWorkerFactory factory1(std::move(factory_request1));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client1.CheckReceivedOnCreated());
// Cleanup
client0.Close();
client1.Close();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker0.CheckReceivedTerminate());
EXPECT_TRUE(worker1.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase) {
const GURL 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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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);
base::RunLoop().RunUntilIdle();
// Check that the worker was created.
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
// Check that the worker received two connections.
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client0.CheckReceivedOnCreated());
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client1.CheckReceivedOnCreated());
// Cleanup
client0.Close();
client1.Close();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_URLMismatch) {
const GURL kUrl0("http://example.com/w0.js");
const GURL 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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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);
base::RunLoop().RunUntilIdle();
// 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));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
// Check that the workers each received a connection.
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(worker0.CheckNotReceivedConnect());
EXPECT_TRUE(client0.CheckReceivedOnCreated());
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(worker1.CheckNotReceivedConnect());
EXPECT_TRUE(client1.CheckReceivedOnCreated());
// Cleanup
client0.Close();
client1.Close();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker0.CheckReceivedTerminate());
EXPECT_TRUE(worker1.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerTest_PendingCase_NameMismatch) {
const GURL 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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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);
base::RunLoop().RunUntilIdle();
// 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));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
// Check that the workers each received a connection.
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(worker0.CheckNotReceivedConnect());
EXPECT_TRUE(client0.CheckReceivedOnCreated());
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(worker1.CheckNotReceivedConnect());
EXPECT_TRUE(client1.CheckReceivedOnCreated());
// Cleanup
client0.Close();
client1.Close();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker0.CheckReceivedTerminate());
EXPECT_TRUE(worker1.CheckReceivedTerminate());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest) {
const GURL 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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
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));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
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));
renderer_host2->OverrideURLLoaderFactory(url_loader_factory_.get());
MockSharedWorkerClient client0;
MessagePortChannel local_port0;
ConnectToSharedWorker(MakeSharedWorkerConnector(
renderer_host0, render_frame_host0->GetRoutingID()),
kUrl, kName, &client0, &local_port0);
base::RunLoop().RunUntilIdle();
// Starts a worker.
mojom::SharedWorkerFactoryRequest factory_request0;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request0));
MockSharedWorkerFactory factory0(std::move(factory_request0));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker0.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(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);
base::RunLoop().RunUntilIdle();
// 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));
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker0.CheckNotReceivedConnect());
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(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);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(CheckNotReceivedFactoryRequest());
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client2.CheckReceivedOnCreated());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest2) {
const GURL 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));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
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));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
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));
renderer_host2->OverrideURLLoaderFactory(url_loader_factory_.get());
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);
base::RunLoop().RunUntilIdle();
// 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());
base::RunLoop().RunUntilIdle();
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));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(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);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(CheckNotReceivedFactoryRequest());
EXPECT_TRUE(worker1.CheckReceivedConnect(nullptr, nullptr));
EXPECT_TRUE(client2.CheckReceivedOnCreated());
}
TEST_F(SharedWorkerServiceImplTest, CreateWorkerRaceTest3) {
const GURL 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::BindRepeating(
&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
// 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::BindRepeating(
&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
// Both clients try to connect/create a worker.
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);
base::RunLoop().RunUntilIdle();
// Expect a factory request.
mojom::SharedWorkerFactoryRequest factory_request;
EXPECT_TRUE(CheckReceivedFactoryRequest(&factory_request));
MockSharedWorkerFactory factory(std::move(factory_request));
base::RunLoop().RunUntilIdle();
// Expect a create shared worker.
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));
base::RunLoop().RunUntilIdle();
// Expect one connect for the first client.
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
client0.CheckReceivedOnCreated();
// Expect one connect for the second client.
EXPECT_TRUE(worker.CheckReceivedConnect(nullptr, nullptr));
client1.CheckReceivedOnCreated();
// Cleanup
client0.Close();
client1.Close();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(worker.CheckReceivedTerminate());
}
} // namespace content