blob: 147afbb446d1e6d72e6b65b466a49daf46a98120 [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 <algorithm>
#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/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
namespace blink {
namespace {
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>> initial_worlds;
DOMWrapperWorld::AllWorldsInCurrentThread(initial_worlds);
EXPECT_TRUE(initial_worlds.IsEmpty());
// Create worlds on the worker thread and verify them.
v8::Isolate* isolate = thread->GetIsolate();
auto worker_world1 =
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker);
auto worker_world2 =
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker);
Vector<scoped_refptr<DOMWrapperWorld>> worlds;
DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
EXPECT_EQ(worlds.size(), initial_worlds.size() + 2);
worlds.clear();
// Dispose of remaining worlds.
worker_world1->Dispose();
worker_world2->Dispose();
worker_world1.reset();
worker_world2.reset();
thread->ShutdownOnBackingThread();
PostCrossThreadTask(*main_thread_task_runner, FROM_HERE,
CrossThreadBindOnce(&test::ExitRunLoop));
}
TEST(DOMWrapperWorldTest, Basic) {
// Initial setup
DOMWrapperWorld& main_world = DOMWrapperWorld::MainWorld();
EXPECT_TRUE(main_world.IsMainWorld());
Vector<scoped_refptr<DOMWrapperWorld>> initial_worlds;
DOMWrapperWorld::AllWorldsInCurrentThread(initial_worlds);
int32_t used_isolated_world_id = DOMWrapperWorld::kMainWorldId;
for (const auto& world : initial_worlds) {
if (world->IsIsolatedWorld()) {
used_isolated_world_id =
std::max(used_isolated_world_id, world->GetWorldId());
}
}
ASSERT_TRUE(DOMWrapperWorld::IsIsolatedWorldId(used_isolated_world_id + 1));
V8TestingScope scope;
v8::Isolate* isolate = scope.GetIsolate();
// Isolated worlds
auto isolated_world1 =
DOMWrapperWorld::EnsureIsolatedWorld(isolate, used_isolated_world_id + 1);
auto isolated_world2 =
DOMWrapperWorld::EnsureIsolatedWorld(isolate, used_isolated_world_id + 2);
EXPECT_TRUE(isolated_world1->IsIsolatedWorld());
EXPECT_TRUE(isolated_world2->IsIsolatedWorld());
Vector<scoped_refptr<DOMWrapperWorld>> worlds;
EXPECT_TRUE(DOMWrapperWorld::NonMainWorldsExistInMainThread());
DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
EXPECT_EQ(worlds.size(), initial_worlds.size() + 2);
worlds.clear();
isolated_world1.reset();
isolated_world2.reset();
DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
EXPECT_EQ(worlds.size(), initial_worlds.size());
worlds.clear();
// Worker worlds
auto worker_world1 =
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker);
auto worker_world2 =
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker);
auto worker_world3 =
DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker);
EXPECT_TRUE(worker_world1->IsWorkerWorld());
EXPECT_TRUE(worker_world2->IsWorkerWorld());
EXPECT_TRUE(worker_world3->IsWorkerWorld());
HashSet<int32_t> worker_world_ids;
EXPECT_TRUE(
worker_world_ids.insert(worker_world1->GetWorldId()).is_new_entry);
EXPECT_TRUE(
worker_world_ids.insert(worker_world2->GetWorldId()).is_new_entry);
EXPECT_TRUE(
worker_world_ids.insert(worker_world3->GetWorldId()).is_new_entry);
EXPECT_TRUE(DOMWrapperWorld::NonMainWorldsExistInMainThread());
DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
EXPECT_EQ(worlds.size(), initial_worlds.size() + 3);
worlds.clear();
worker_world1->Dispose();
worker_world2->Dispose();
worker_world3->Dispose();
worker_world1.reset();
worker_world2.reset();
worker_world3.reset();
DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
EXPECT_EQ(worlds.size(), initial_worlds.size());
worlds.clear();
// Start a worker thread and create worlds on that.
std::unique_ptr<WorkerBackingThread> thread =
std::make_unique<WorkerBackingThread>(
ThreadCreationParams(ThreadType::kTestThread)
.SetThreadNameForTest("DOMWrapperWorld test thread"));
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner =
Thread::Current()->GetTaskRunner();
PostCrossThreadTask(*thread->BackingThread().GetTaskRunner(), FROM_HERE,
CrossThreadBindOnce(&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.
DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
EXPECT_EQ(worlds.size(), initial_worlds.size());
worlds.clear();
}
} // namespace
} // namespace blink