Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(752)

Unified Diff: third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp

Issue 2124693002: Worker: Fix broken GC logic on Dedicated Worker while DOMTimer is set (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..5aa4ac889280d0ec74705c8523a426514196283c
--- /dev/null
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
@@ -0,0 +1,314 @@
+// 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");
+ }
+
+ WorkerOrWorkletGlobalScope* 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 /* workerObject */ , nullptr /* workerClients */)
+ {
+ workerObjectProxy().m_nextIntervalInSec = 0.1;
+ workerObjectProxy().m_maxIntervalInSec = 0.2;
+
+ m_mockWorkerLoaderProxyProvider = wrapUnique(new MockWorkerLoaderProxyProvider());
+ m_workerThread = wrapUnique(new DedicatedWorkerThreadForTest(m_mockWorkerLoaderProxyProvider.get(), workerObjectProxy()));
+ workerThreadCreated();
+
+ 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,
+ MessageConfirmed,
+ PendingActivityReported,
+ 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 confirmMessageFromWorkerObject() override
+ {
+ EXPECT_TRUE(isMainThread());
+ InProcessWorkerMessagingProxy::confirmMessageFromWorkerObject();
+ if (m_waitUntilMode != WaitUntilMode::MessageConfirmed)
+ return;
+ m_waitUntilMode = WaitUntilMode::DontWait;
+ testing::exitRunLoop();
+ }
+
+ void pendingActivityFinished() override
+ {
+ EXPECT_TRUE(isMainThread());
+ InProcessWorkerMessagingProxy::pendingActivityFinished();
+ if (m_waitUntilMode != WaitUntilMode::PendingActivityReported)
+ return;
+ 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());
+ }
+
+ bool workerGlobalScopeMayHavePendingActivity() const { return m_workerGlobalScopeMayHavePendingActivity; }
+ unsigned unconfirmedMessageCount() const { return m_unconfirmedMessageCount; }
+
+private:
+ std::unique_ptr<MockWorkerLoaderProxyProvider> m_mockWorkerLoaderProxyProvider;
+ 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 dispatchMessageEvent()
+ {
+ workerMessagingProxy()->postMessageToWorkerGlobalScope(nullptr /* message */, nullptr /* channels */);
+ }
+
+ 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);
+
+ // Worker initialization should be counted as a pending activity.
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // There should be no pending activities after the initialization.
+ 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);
+
+ // Worker initialization should be counted as a pending activity.
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // The timer is fired soon and there should be no pending activities after
+ // that.
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported);
+ 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() {}, 50);"
+ "addEventListener('message', function(event) { clearInterval(id); });";
+ startWithSourceCode(sourceCode);
+
+ // Worker initialization should be counted as a pending activity.
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // Stop the timer.
+ dispatchMessageEvent();
+ EXPECT_EQ(1u, workerMessagingProxy()->unconfirmedMessageCount());
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+ workerMessagingProxy()->waitUntil(WaitUntilMode::MessageConfirmed);
+ EXPECT_EQ(0u, workerMessagingProxy()->unconfirmedMessageCount());
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // There should be no pending activities after the timer is stopped.
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported);
+ EXPECT_FALSE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+}
+
+TEST_F(DedicatedWorkerTest, PendingActivity_SetTimeoutOnMessageEvent)
+{
+ // Start an oneshot timer on a message event.
+ const String sourceCode =
+ "addEventListener('message', function(event) {"
+ " setTimeout(function() {}, 50);"
+ "});";
+ startWithSourceCode(sourceCode);
+
+ // Worker initialization should be counted as a pending activity.
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported);
+ EXPECT_FALSE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // A message starts the oneshot timer that is counted as a pending activity.
+ dispatchMessageEvent();
+ EXPECT_EQ(1u, workerMessagingProxy()->unconfirmedMessageCount());
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+ workerMessagingProxy()->waitUntil(WaitUntilMode::MessageConfirmed);
+ EXPECT_EQ(0u, workerMessagingProxy()->unconfirmedMessageCount());
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // The timer is fired soon and there should be no pending activities after
+ // that.
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported);
+ EXPECT_FALSE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+}
+
+TEST_F(DedicatedWorkerTest, PendingActivity_SetIntervalOnMessageEvent)
+{
+ // Start a repeated timer on a message event, and stop it when another
+ // message is received.
+ const String sourceCode =
+ "var count = 0;"
+ "var id;"
+ "addEventListener('message', function(event) {"
+ " if (count++ == 0) {"
+ " id = setInterval(function() {}, 50);"
+ " } else {"
+ " clearInterval(id);"
+ " }"
+ "});";
+ startWithSourceCode(sourceCode);
+
+ // Worker initialization should be counted as a pending activity.
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported);
+ EXPECT_FALSE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // The first message event sets the active timer that is counted as a
+ // pending activity.
+ dispatchMessageEvent();
+ EXPECT_EQ(1u, workerMessagingProxy()->unconfirmedMessageCount());
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+ workerMessagingProxy()->waitUntil(WaitUntilMode::MessageConfirmed);
+ EXPECT_EQ(0u, workerMessagingProxy()->unconfirmedMessageCount());
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // Run the message loop for a while to make sure the timer is counted as a
+ // pending activity until it's stopped.
+ testing::runDelayedTasks(1000);
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // Stop the timer.
+ dispatchMessageEvent();
+ EXPECT_EQ(1u, workerMessagingProxy()->unconfirmedMessageCount());
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+ workerMessagingProxy()->waitUntil(WaitUntilMode::MessageConfirmed);
+ EXPECT_EQ(0u, workerMessagingProxy()->unconfirmedMessageCount());
+ EXPECT_TRUE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+
+ // There should be no pending activities after the timer is stopped.
+ workerMessagingProxy()->waitUntil(WaitUntilMode::PendingActivityReported);
+ EXPECT_FALSE(workerMessagingProxy()->workerGlobalScopeMayHavePendingActivity());
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698