Index: third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp |
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3ebc568c39a2755491eac5d115a7e776da0962e6 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp |
@@ -0,0 +1,227 @@ |
+// Copyright 2016 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 "core/dom/CrossThreadTask.h" |
+#include "core/events/MessageEvent.h" |
+#include "core/testing/DummyPageHolder.h" |
+#include "core/workers/DedicatedWorkerGlobalScope.h" |
+#include "core/workers/DedicatedWorkerThread.h" |
+#include "core/workers/InProcessWorkerMessagingProxy.h" |
+#include "core/workers/InProcessWorkerObjectProxy.h" |
+#include "core/workers/WorkerThread.h" |
+#include "core/workers/WorkerThreadStartupData.h" |
+#include "core/workers/WorkerThreadTestHelper.h" |
+#include "platform/testing/UnitTestHelpers.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include <memory> |
+ |
+namespace blink { |
+ |
+class DedicatedWorkerThreadForTest final : public DedicatedWorkerThread { |
+public: |
+ DedicatedWorkerThreadForTest( |
+ WorkerLoaderProxyProvider* workerLoaderProxyProvider, |
+ InProcessWorkerObjectProxy& workerObjectProxy) |
+ : DedicatedWorkerThread(WorkerLoaderProxy::create(workerLoaderProxyProvider), workerObjectProxy, monotonicallyIncreasingTime()) |
+ { |
+ m_workerBackingThread = WorkerBackingThread::createForTest("Test thread"); |
+ } |
+ |
+ WorkerGlobalScope* createWorkerGlobalScope(std::unique_ptr<WorkerThreadStartupData> startupData) override |
+ { |
+ return new DedicatedWorkerGlobalScope(startupData->m_scriptURL, startupData->m_userAgent, this, m_timeOrigin, std::move(startupData->m_starterOriginPrivilegeData), std::move(startupData->m_workerClients)); |
+ }; |
+}; |
+ |
+class InProcessWorkerMessagingProxyForTest : public InProcessWorkerMessagingProxy { |
+public: |
+ InProcessWorkerMessagingProxyForTest(ExecutionContext* executionContext) |
+ : InProcessWorkerMessagingProxy(executionContext, nullptr, nullptr) |
+ { |
+ workerObjectProxy().m_maxDelayToCheckPendingActivityInMs = 1000; // 1 sec |
+ |
+ m_mockWorkerLoaderProxyProvider = wrapUnique(new MockWorkerLoaderProxyProvider()); |
+ m_workerThread = wrapUnique(new DedicatedWorkerThreadForTest(m_mockWorkerLoaderProxyProvider.get(), workerObjectProxy())); |
+ |
+ m_mockWorkerThreadLifecycleObserver = new MockWorkerThreadLifecycleObserver(m_workerThread->getWorkerThreadLifecycleContext()); |
+ EXPECT_CALL(*m_mockWorkerThreadLifecycleObserver, contextDestroyed()).Times(1); |
+ } |
+ |
+ ~InProcessWorkerMessagingProxyForTest() override |
+ { |
+ EXPECT_EQ(WaitUntilMode::DontWait, m_waitUntilMode); |
+ m_workerThread->workerLoaderProxy()->detachProvider(m_mockWorkerLoaderProxyProvider.get()); |
+ } |
+ |
+ enum class WaitUntilMode { |
+ DontWait, |
+ PendingActivityReported, |
+ PendingActivityChanged, |
+ ThreadTerminated, |
+ }; |
+ |
+ // Blocks the main thread until a specified event happens. |
+ void waitUntil(WaitUntilMode mode) |
+ { |
+ EXPECT_TRUE(isMainThread()); |
+ EXPECT_EQ(WaitUntilMode::DontWait, m_waitUntilMode); |
+ m_waitUntilMode = mode; |
+ testing::enterRunLoop(); |
+ } |
+ |
+ void reportPendingActivity(bool hasPendingActivity) override |
+ { |
+ EXPECT_TRUE(isMainThread()); |
+ bool changed = m_workerThreadHadPendingActivity != hasPendingActivity; |
+ InProcessWorkerMessagingProxy::reportPendingActivity(hasPendingActivity); |
+ |
+ if (m_waitUntilMode == WaitUntilMode::PendingActivityReported || (m_waitUntilMode == WaitUntilMode::PendingActivityChanged && changed)) { |
+ m_waitUntilMode = WaitUntilMode::DontWait; |
+ testing::exitRunLoop(); |
+ } |
+ } |
+ |
+ void workerThreadTerminated() override |
+ { |
+ EXPECT_TRUE(isMainThread()); |
+ if (m_waitUntilMode != WaitUntilMode::ThreadTerminated) |
+ return; |
+ m_waitUntilMode = WaitUntilMode::DontWait; |
+ testing::exitRunLoop(); |
+ } |
+ |
+ std::unique_ptr<WorkerThread> createWorkerThread(double originTime) override |
+ { |
+ NOTREACHED(); |
+ return nullptr; |
+ } |
+ |
+ DedicatedWorkerThreadForTest* workerThread() |
+ { |
+ return static_cast<DedicatedWorkerThreadForTest*>(m_workerThread.get()); |
+ } |
+ |
+private: |
+ std::unique_ptr<MockWorkerLoaderProxyProvider> m_mockWorkerLoaderProxyProvider; |
+ std::unique_ptr<DedicatedWorkerThreadForTest> m_workerThread; |
+ Persistent<MockWorkerThreadLifecycleObserver> m_mockWorkerThreadLifecycleObserver; |
+ |
+ WaitUntilMode m_waitUntilMode = WaitUntilMode::DontWait; |
+}; |
+ |
+using WaitUntilMode = InProcessWorkerMessagingProxyForTest::WaitUntilMode; |
+ |
+class DedicatedWorkerTest : public ::testing::Test { |
+public: |
+ void SetUp() override |
+ { |
+ m_page = DummyPageHolder::create(); |
+ m_workerMessagingProxy = wrapUnique(new InProcessWorkerMessagingProxyForTest(&m_page->document())); |
+ m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http://fake.url/")); |
+ } |
+ |
+ void TearDown() override |
+ { |
+ workerThread()->terminate(); |
+ workerMessagingProxy()->waitUntil(WaitUntilMode::ThreadTerminated); |
+ } |
+ |
+ void startWithSourceCode(const String& source) |
+ { |
+ std::unique_ptr<Vector<CSPHeaderAndType>> headers = wrapUnique(new Vector<CSPHeaderAndType>()); |
+ CSPHeaderAndType headerAndType("contentSecurityPolicy", ContentSecurityPolicyHeaderTypeReport); |
+ headers->append(headerAndType); |
+ workerThread()->start(WorkerThreadStartupData::create( |
+ KURL(ParsedURLString, "http://fake.url/"), |
+ "fake user agent", |
+ source, |
+ nullptr /* cachedMetaData */, |
+ DontPauseWorkerGlobalScopeOnStart, |
+ headers.get(), |
+ "" /* referrerPolicy */, |
+ m_securityOrigin.get(), |
+ nullptr /* workerClients */, |
+ WebAddressSpaceLocal, |
+ nullptr /* originTrialTokens */, |
+ nullptr /* workerSettings */, |
+ V8CacheOptionsDefault)); |
+ } |
+ |
+ void dispatchMessageEventOnWorkerThread() |
+ { |
+ toWorkerGlobalScope(workerThread()->globalScope())->dispatchEvent(MessageEvent::create(nullptr, SerializedScriptValue::create())); |
+ } |
+ |
+ InProcessWorkerMessagingProxyForTest* workerMessagingProxy() |
+ { |
+ return m_workerMessagingProxy.get(); |
+ } |
+ |
+ DedicatedWorkerThreadForTest* workerThread() |
+ { |
+ return m_workerMessagingProxy->workerThread(); |
+ } |
+ |
+private: |
+ RefPtr<SecurityOrigin> m_securityOrigin; |
+ std::unique_ptr<DummyPageHolder> m_page; |
+ std::unique_ptr<InProcessWorkerMessagingProxyForTest> m_workerMessagingProxy; |
+}; |
+ |
+TEST_F(DedicatedWorkerTest, PendingActivity_NoActivity) |
+{ |
+ const String sourceCode = "// Do nothing"; |
+ startWithSourceCode(sourceCode); |
+ EXPECT_FALSE(workerMessagingProxy()->hasPendingActivity()); |
+ |
+ // There should be no pending activities. |
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported); |
+ EXPECT_FALSE(workerMessagingProxy()->hasPendingActivity()); |
+} |
+ |
+TEST_F(DedicatedWorkerTest, PendingActivity_SetTimeout) |
+{ |
+ // Start an oneshot timer on initial script evaluation. |
+ const String sourceCode = "setTimeout(function() {}, 50);"; |
+ |
+ startWithSourceCode(sourceCode); |
+ EXPECT_FALSE(workerMessagingProxy()->hasPendingActivity()); |
+ |
+ // The initial report should be true because the active timer is counted as |
+ // a pending activity. |
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported); |
+ EXPECT_TRUE(workerMessagingProxy()->hasPendingActivity()); |
+ |
+ // The timer is fired soon and there should be no pending activities after |
+ // that. |
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityChanged); |
+ EXPECT_FALSE(workerMessagingProxy()->hasPendingActivity()); |
+} |
+ |
+TEST_F(DedicatedWorkerTest, PendingActivity_SetInterval) |
+{ |
+ // Start a repeated timer on initial script evaluation, and stop it when a |
+ // message is received. |
+ const String sourceCode = |
+ "var id = setInterval(function() {}, 1000);" |
+ "addEventListener('message', function(event) { clearInterval(id); });"; |
+ |
+ startWithSourceCode(sourceCode); |
+ EXPECT_FALSE(workerMessagingProxy()->hasPendingActivity()); |
+ |
+ // The initial report should be true because the active timer is counted as |
+ // a pending activity. |
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported); |
+ EXPECT_TRUE(workerMessagingProxy()->hasPendingActivity()); |
+ |
+ // Stop the timer. |
+ workerThread()->postTask(BLINK_FROM_HERE, createCrossThreadTask(&DedicatedWorkerTest::dispatchMessageEventOnWorkerThread, crossThreadUnretained(this))); |
+ |
+ // There should be no pending activities after the timer is stopped. |
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityChanged); |
+ EXPECT_FALSE(workerMessagingProxy()->hasPendingActivity()); |
+} |
+ |
+} // namespace blink |