blob: ef15fb17869f71d08f8eab8a77517d37b0f03874 [file] [log] [blame]
// Copyright 2017 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 "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "base/single_thread_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_initializer.h"
#include "third_party/blink/renderer/core/workers/worker_backing_thread.h"
#include "third_party/blink/renderer/core/workers/worker_backing_thread_startup_data.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/web_thread_supporting_gc.h"
namespace blink {
namespace {
Vector<scoped_refptr<DOMWrapperWorld>> CreateIsolatedWorlds(
v8::Isolate* isolate) {
Vector<scoped_refptr<DOMWrapperWorld>> worlds;
worlds.push_back(DOMWrapperWorld::EnsureIsolatedWorld(
isolate, DOMWrapperWorld::WorldId::kMainWorldId + 1));
worlds.push_back(DOMWrapperWorld::EnsureIsolatedWorld(
isolate, DOMWrapperWorld::WorldId::kIsolatedWorldIdLimit - 1));
EXPECT_TRUE(worlds[0]->IsIsolatedWorld());
EXPECT_TRUE(worlds[1]->IsIsolatedWorld());
return worlds;
}
Vector<scoped_refptr<DOMWrapperWorld>> CreateWorlds(v8::Isolate* isolate) {
Vector<scoped_refptr<DOMWrapperWorld>> worlds;
worlds.push_back(
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker));
worlds.push_back(
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker));
worlds.push_back(
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker));
EXPECT_TRUE(worlds[0]->IsWorkerWorld());
EXPECT_TRUE(worlds[1]->IsWorkerWorld());
EXPECT_TRUE(worlds[2]->IsWorkerWorld());
// World ids should be unique.
HashSet<int> world_ids;
EXPECT_TRUE(world_ids.insert(worlds[0]->GetWorldId()).is_new_entry);
EXPECT_TRUE(world_ids.insert(worlds[1]->GetWorldId()).is_new_entry);
EXPECT_TRUE(world_ids.insert(worlds[2]->GetWorldId()).is_new_entry);
return worlds;
}
void WorkerThreadFunc(
WorkerBackingThread* thread,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) {
thread->InitializeOnBackingThread(
WorkerBackingThreadStartupData::CreateDefault());
// Worlds on the main thread should not be visible from the worker thread.
Vector<scoped_refptr<DOMWrapperWorld>> retrieved_worlds;
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_TRUE(retrieved_worlds.IsEmpty());
// Create worlds on the worker thread and verify them.
Vector<scoped_refptr<DOMWrapperWorld>> worlds =
CreateWorlds(thread->GetIsolate());
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_EQ(worlds.size(), retrieved_worlds.size());
retrieved_worlds.clear();
// Dispose of remaining worlds.
for (scoped_refptr<DOMWrapperWorld>& world : worlds) {
if (world->IsWorkerWorld())
world->Dispose();
}
worlds.clear();
thread->ShutdownOnBackingThread();
PostCrossThreadTask(*main_thread_task_runner, FROM_HERE,
CrossThreadBind(&test::ExitRunLoop));
}
TEST(DOMWrapperWorldTest, Basic) {
// Create the main world and verify it.
DOMWrapperWorld& main_world = DOMWrapperWorld::MainWorld();
EXPECT_TRUE(main_world.IsMainWorld());
EXPECT_FALSE(DOMWrapperWorld::NonMainWorldsExistInMainThread());
Vector<scoped_refptr<DOMWrapperWorld>> retrieved_worlds;
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_EQ(1u, retrieved_worlds.size());
EXPECT_TRUE(retrieved_worlds[0]->IsMainWorld());
retrieved_worlds.clear();
// Create isolated worlds and verify them.
V8TestingScope scope;
Vector<scoped_refptr<DOMWrapperWorld>> isolated_worlds =
CreateIsolatedWorlds(scope.GetIsolate());
EXPECT_TRUE(DOMWrapperWorld::NonMainWorldsExistInMainThread());
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_EQ(isolated_worlds.size() + 1, retrieved_worlds.size());
// Create other worlds and verify them.
Vector<scoped_refptr<DOMWrapperWorld>> worlds =
CreateWorlds(scope.GetIsolate());
EXPECT_TRUE(DOMWrapperWorld::NonMainWorldsExistInMainThread());
retrieved_worlds.clear();
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_EQ(isolated_worlds.size() + worlds.size() + 1,
retrieved_worlds.size());
retrieved_worlds.clear();
// Start a worker thread and create worlds on that.
std::unique_ptr<WorkerBackingThread> thread = WorkerBackingThread::Create(
ThreadCreationParams(WebThreadType::kTestThread)
.SetThreadNameForTest("DOMWrapperWorld test thread"));
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner =
Platform::Current()->CurrentThread()->GetTaskRunner();
thread->BackingThread().PostTask(
FROM_HERE,
CrossThreadBind(&WorkerThreadFunc, CrossThreadUnretained(thread.get()),
std::move(main_thread_task_runner)));
test::EnterRunLoop();
// Worlds on the worker thread should not be visible from the main thread.
EXPECT_TRUE(DOMWrapperWorld::NonMainWorldsExistInMainThread());
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_EQ(isolated_worlds.size() + worlds.size() + 1,
retrieved_worlds.size());
retrieved_worlds.clear();
// Dispose of the isolated worlds.
isolated_worlds.clear();
EXPECT_TRUE(DOMWrapperWorld::NonMainWorldsExistInMainThread());
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_EQ(worlds.size() + 1, retrieved_worlds.size());
retrieved_worlds.clear();
// Dispose of the other worlds.
for (scoped_refptr<DOMWrapperWorld>& world : worlds) {
if (world->IsWorkerWorld())
world->Dispose();
}
worlds.clear();
EXPECT_FALSE(DOMWrapperWorld::NonMainWorldsExistInMainThread());
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_EQ(1u, retrieved_worlds.size());
}
} // namespace
} // namespace blink