blob: 273915768c7a30e27e64a64d2523104bdbac730f [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 "platform/bindings/DOMWrapperWorld.h"
#include "base/single_thread_task_runner.h"
#include "bindings/core/v8/V8BindingForTesting.h"
#include "bindings/core/v8/V8Initializer.h"
#include "core/workers/WorkerBackingThread.h"
#include "core/workers/WorkerBackingThreadStartupData.h"
#include "platform/CrossThreadFunctional.h"
#include "platform/WebThreadSupportingGC.h"
#include "platform/bindings/V8PerIsolateData.h"
#include "platform/testing/UnitTestHelpers.h"
#include "public/platform/Platform.h"
#include "testing/gtest/include/gtest/gtest.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::kGarbageCollector));
EXPECT_TRUE(worlds[0]->IsWorkerWorld());
EXPECT_TRUE(worlds[1]->IsWorkerWorld());
EXPECT_FALSE(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 the last world.
worlds.pop_back();
DOMWrapperWorld::AllWorldsInCurrentThread(retrieved_worlds);
EXPECT_EQ(worlds.size(), retrieved_worlds.size());
// 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(&testing::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(
WebThreadCreationParams(WebThreadType::kTestThread)
.SetThreadName("DOMWrapperWorld test thread"));
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner =
Platform::Current()->CurrentThread()->GetWebTaskRunner();
thread->BackingThread().PostTask(
FROM_HERE,
CrossThreadBind(&WorkerThreadFunc, CrossThreadUnretained(thread.get()),
std::move(main_thread_task_runner)));
testing::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