Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / modules / compositorworker / CompositorWorkerManagerTest.cpp
blobff8fe0359e27242342492f1713d6f3fd553b5553
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "config.h"
6 #include "modules/compositorworker/CompositorWorkerManager.h"
8 #include "bindings/core/v8/ScriptSourceCode.h"
9 #include "bindings/core/v8/V8GCController.h"
10 #include "core/inspector/ConsoleMessage.h"
11 #include "core/testing/DummyPageHolder.h"
12 #include "core/workers/WorkerLoaderProxy.h"
13 #include "core/workers/WorkerObjectProxy.h"
14 #include "core/workers/WorkerThreadStartupData.h"
15 #include "modules/compositorworker/CompositorWorkerThread.h"
16 #include "platform/NotImplemented.h"
17 #include "platform/ThreadSafeFunctional.h"
18 #include "platform/heap/Handle.h"
19 #include "platform/testing/UnitTestHelpers.h"
20 #include "public/platform/Platform.h"
21 #include "public/platform/WebWaitableEvent.h"
22 #include <gtest/gtest.h>
24 namespace blink {
25 namespace {
27 class TestCompositorWorkerThread : public CompositorWorkerThread {
28 public:
29 TestCompositorWorkerThread(WorkerLoaderProxyProvider* loaderProxyProvider, WorkerObjectProxy& objectProxy, double timeOrigin, WebWaitableEvent* startEvent)
30 : CompositorWorkerThread(WorkerLoaderProxy::create(loaderProxyProvider), objectProxy, timeOrigin)
31 , m_startEvent(startEvent)
35 ~TestCompositorWorkerThread() override { }
37 void setCallbackAfterV8Termination(PassOwnPtr<Function<void()>> callback)
39 m_v8TerminationCallback = callback;
42 private:
43 // WorkerThread:
44 void didStartRunLoop() override
46 m_startEvent->signal();
48 void terminateV8Execution() override
50 CompositorWorkerThread::terminateV8Execution();
51 if (m_v8TerminationCallback)
52 (*m_v8TerminationCallback)();
54 void willDestroyIsolate() override
56 V8GCController::collectAllGarbageForTesting(v8::Isolate::GetCurrent());
57 CompositorWorkerThread::willDestroyIsolate();
60 WebWaitableEvent* m_startEvent;
61 OwnPtr<Function<void()>> m_v8TerminationCallback;
64 // A null WorkerObjectProxy, supplied when creating CompositorWorkerThreads.
65 class TestCompositorWorkerObjectProxy : public WorkerObjectProxy {
66 public:
67 static PassOwnPtr<TestCompositorWorkerObjectProxy> create(ExecutionContext* context)
69 return adoptPtr(new TestCompositorWorkerObjectProxy(context));
72 // (Empty) WorkerReportingProxy implementation:
73 virtual void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, int exceptionId) { }
74 void reportConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage>) override { }
75 void postMessageToPageInspector(const String&) override { }
76 void postWorkerConsoleAgentEnabled() override { }
78 void didEvaluateWorkerScript(bool success) override { }
79 void workerGlobalScopeStarted(WorkerGlobalScope*) override { }
80 void workerGlobalScopeClosed() override { }
81 void workerThreadTerminated() override { }
82 void willDestroyWorkerGlobalScope() override { }
83 private:
84 TestCompositorWorkerObjectProxy(ExecutionContext* context)
85 : WorkerObjectProxy(context, nullptr)
90 } // namespace
92 class CompositorWorkerManagerTest : public ::testing::Test {
93 public:
94 void SetUp() override
96 m_page = DummyPageHolder::create();
97 m_objectProxy = TestCompositorWorkerObjectProxy::create(&m_page->document());
98 m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http://fake.url/"));
101 void TearDown() override
103 ASSERT(!managerHasThread());
104 ASSERT(!managerHasIsolate());
105 m_page.clear();
108 PassRefPtr<TestCompositorWorkerThread> createCompositorWorker(WebWaitableEvent* startEvent)
110 TestCompositorWorkerThread* workerThread = new TestCompositorWorkerThread(nullptr, *m_objectProxy, 0, startEvent);
111 OwnPtrWillBeRawPtr<WorkerClients> clients = nullptr;
112 workerThread->start(WorkerThreadStartupData::create(
113 KURL(ParsedURLString, "http://fake.url/"),
114 "fake user agent",
115 "//fake source code",
116 nullptr,
117 DontPauseWorkerGlobalScopeOnStart,
118 adoptPtr(new Vector<CSPHeaderAndType>()),
119 m_securityOrigin.get(),
120 clients.release(),
121 V8CacheOptionsDefault));
122 return adoptRef(workerThread);
125 void createWorkerAdapter(RefPtr<CompositorWorkerThread>* workerThread, WebWaitableEvent* creationEvent)
127 *workerThread = createCompositorWorker(creationEvent);
130 // Attempts to run some simple script for |worker|.
131 void checkWorkerCanExecuteScript(WorkerThread* worker)
133 OwnPtr<WebWaitableEvent> waitEvent = adoptPtr(Platform::current()->createWaitableEvent());
134 worker->backingThread().platformThread().taskRunner()->postTask(FROM_HERE, threadSafeBind(&CompositorWorkerManagerTest::executeScriptInWorker, AllowCrossThreadAccess(this),
135 AllowCrossThreadAccess(worker), AllowCrossThreadAccess(waitEvent.get())));
136 waitEvent->wait();
139 void waitForWaitableEventAfterIteratingCurrentLoop(WebWaitableEvent* waitEvent)
141 testing::runPendingTasks();
142 waitEvent->wait();
145 bool managerHasThread() const
147 return CompositorWorkerManager::instance()->m_thread;
150 bool managerHasIsolate() const
152 return CompositorWorkerManager::instance()->m_isolate;
155 private:
156 void executeScriptInWorker(WorkerThread* worker, WebWaitableEvent* waitEvent)
158 WorkerScriptController* scriptController = worker->workerGlobalScope()->script();
159 bool evaluateResult = scriptController->evaluate(ScriptSourceCode("var counter = 0; ++counter;"));
160 ASSERT_UNUSED(evaluateResult, evaluateResult);
161 waitEvent->signal();
164 OwnPtr<DummyPageHolder> m_page;
165 RefPtr<SecurityOrigin> m_securityOrigin;
166 OwnPtr<WorkerObjectProxy> m_objectProxy;
169 TEST_F(CompositorWorkerManagerTest, Basic)
171 OwnPtr<WebWaitableEvent> creationEvent = adoptPtr(Platform::current()->createWaitableEvent());
172 RefPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker(creationEvent.get());
173 waitForWaitableEventAfterIteratingCurrentLoop(creationEvent.get());
174 checkWorkerCanExecuteScript(compositorWorker.get());
175 compositorWorker->terminateAndWait();
178 // Tests that the same WebThread is used for new workers if the WebThread is still alive.
179 TEST_F(CompositorWorkerManagerTest, CreateSecondAndTerminateFirst)
181 // Create the first worker and wait until it is initialized.
182 OwnPtr<WebWaitableEvent> firstCreationEvent = adoptPtr(Platform::current()->createWaitableEvent());
183 RefPtr<CompositorWorkerThread> firstWorker = createCompositorWorker(firstCreationEvent.get());
184 WebThreadSupportingGC* firstThread = &CompositorWorkerManager::instance()->compositorWorkerThread();
185 ASSERT(firstThread);
186 waitForWaitableEventAfterIteratingCurrentLoop(firstCreationEvent.get());
187 v8::Isolate* firstIsolate = firstWorker->isolate();
188 ASSERT(firstIsolate);
190 // Create the second worker and immediately destroy the first worker.
191 OwnPtr<WebWaitableEvent> secondCreationEvent = adoptPtr(Platform::current()->createWaitableEvent());
192 RefPtr<CompositorWorkerThread> secondWorker = createCompositorWorker(secondCreationEvent.get());
193 firstWorker->terminateAndWait();
195 // Wait until the second worker is initialized. Verify that the second worker is using the same
196 // thread and Isolate as the first worker.
197 WebThreadSupportingGC* secondThread = &CompositorWorkerManager::instance()->compositorWorkerThread();
198 ASSERT(secondThread);
199 waitForWaitableEventAfterIteratingCurrentLoop(secondCreationEvent.get());
200 EXPECT_EQ(firstThread, secondThread);
202 v8::Isolate* secondIsolate = secondWorker->isolate();
203 ASSERT(secondIsolate);
204 EXPECT_EQ(firstIsolate, secondIsolate);
206 // Verify that the worker can still successfully execute script.
207 checkWorkerCanExecuteScript(secondWorker.get());
209 secondWorker->terminateAndWait();
212 static void checkCurrentIsolate(v8::Isolate* isolate, WebWaitableEvent* event)
214 EXPECT_EQ(v8::Isolate::GetCurrent(), isolate);
215 event->signal();
218 // Tests that a new WebThread is created if all existing workers are terminated before a new worker is created.
219 TEST_F(CompositorWorkerManagerTest, TerminateFirstAndCreateSecond)
221 // Create the first worker, wait until it is initialized, and terminate it.
222 OwnPtr<WebWaitableEvent> creationEvent = adoptPtr(Platform::current()->createWaitableEvent());
223 RefPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker(creationEvent.get());
224 WebThreadSupportingGC* firstThread = &CompositorWorkerManager::instance()->compositorWorkerThread();
225 waitForWaitableEventAfterIteratingCurrentLoop(creationEvent.get());
226 ASSERT(compositorWorker->isolate());
227 compositorWorker->terminateAndWait();
229 // Create the second worker. Verify that the second worker lives in a different WebThread since the first
230 // thread will have been destroyed after destroying the first worker.
231 creationEvent = adoptPtr(Platform::current()->createWaitableEvent());
232 compositorWorker = createCompositorWorker(creationEvent.get());
233 WebThreadSupportingGC* secondThread = &CompositorWorkerManager::instance()->compositorWorkerThread();
234 EXPECT_NE(firstThread, secondThread);
235 waitForWaitableEventAfterIteratingCurrentLoop(creationEvent.get());
237 // Jump over to the worker's thread to verify that the Isolate is set up correctly and execute script.
238 OwnPtr<WebWaitableEvent> checkEvent = adoptPtr(Platform::current()->createWaitableEvent());
239 secondThread->platformThread().taskRunner()->postTask(FROM_HERE, threadSafeBind(&checkCurrentIsolate, AllowCrossThreadAccess(compositorWorker->isolate()), AllowCrossThreadAccess(checkEvent.get())));
240 waitForWaitableEventAfterIteratingCurrentLoop(checkEvent.get());
241 checkWorkerCanExecuteScript(compositorWorker.get());
243 compositorWorker->terminateAndWait();
246 // Tests that v8::Isolate and WebThread are correctly set-up if a worker is created while another is terminating.
247 TEST_F(CompositorWorkerManagerTest, CreatingSecondDuringTerminationOfFirst)
249 OwnPtr<WebWaitableEvent> firstCreationEvent = adoptPtr(Platform::current()->createWaitableEvent());
250 RefPtr<TestCompositorWorkerThread> firstWorker = createCompositorWorker(firstCreationEvent.get());
251 waitForWaitableEventAfterIteratingCurrentLoop(firstCreationEvent.get());
252 v8::Isolate* firstIsolate = firstWorker->isolate();
253 ASSERT(firstIsolate);
255 // Request termination of the first worker, and set-up to make sure the second worker is created right as
256 // the first worker terminates its isolate.
257 OwnPtr<WebWaitableEvent> secondCreationEvent = adoptPtr(Platform::current()->createWaitableEvent());
258 RefPtr<CompositorWorkerThread> secondWorker;
259 firstWorker->setCallbackAfterV8Termination(bind(&CompositorWorkerManagerTest::createWorkerAdapter, this, &secondWorker, secondCreationEvent.get()));
260 firstWorker->terminateAndWait();
261 ASSERT(secondWorker);
263 waitForWaitableEventAfterIteratingCurrentLoop(secondCreationEvent.get());
264 v8::Isolate* secondIsolate = secondWorker->isolate();
265 ASSERT(secondIsolate);
266 EXPECT_EQ(firstIsolate, secondIsolate);
268 // Verify that the isolate can run some scripts correctly in the second worker.
269 checkWorkerCanExecuteScript(secondWorker.get());
270 secondWorker->terminateAndWait();
273 } // namespace blink