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