| // 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 |