OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "config.h" |
| 6 #include "core/workers/WorkerThread.h" |
| 7 |
| 8 #include "bindings/core/v8/ScriptWrappable.h" |
| 9 #include "core/inspector/ConsoleMessage.h" |
| 10 #include "core/workers/SharedWorkerGlobalScope.h" |
| 11 #include "core/workers/SharedWorkerThread.h" |
| 12 #include "core/workers/WorkerGlobalScope.h" |
| 13 #include "core/workers/WorkerReportingProxy.h" |
| 14 #include "core/workers/WorkerThreadStartupData.h" |
| 15 #include <gmock/gmock.h> |
| 16 #include <gtest/gtest.h> |
| 17 |
| 18 using testing::_; |
| 19 using testing::Invoke; |
| 20 using testing::Return; |
| 21 using testing::Mock; |
| 22 |
| 23 namespace blink { |
| 24 |
| 25 namespace { |
| 26 class MockWorkerLoaderProxy : public WorkerLoaderProxy { |
| 27 public: |
| 28 MockWorkerLoaderProxy() : WorkerLoaderProxy(nullptr) { } |
| 29 ~MockWorkerLoaderProxy() override { } |
| 30 |
| 31 MOCK_METHOD1(postTaskToLoader, void(PassOwnPtr<ExecutionContextTask>)); |
| 32 MOCK_METHOD1(postTaskToWorkerGlobalScope, bool(PassOwnPtr<ExecutionContextTa
sk>)); |
| 33 }; |
| 34 |
| 35 class MockWorkerReportingProxy : public WorkerReportingProxy { |
| 36 public: |
| 37 MockWorkerReportingProxy() { } |
| 38 ~MockWorkerReportingProxy() override { } |
| 39 |
| 40 MOCK_METHOD5(reportException, void(const String& errorMessage, int lineNumbe
r, int columnNumber, const String& sourceURL, int exceptionId)); |
| 41 MOCK_METHOD1(reportConsoleMessage, void(PassRefPtrWillBeRawPtr<ConsoleMessag
e>)); |
| 42 MOCK_METHOD1(postMessageToPageInspector, void(const String&)); |
| 43 MOCK_METHOD0(postWorkerConsoleAgentEnabled, void()); |
| 44 MOCK_METHOD1(didEvaluateWorkerScript, void(bool success)); |
| 45 MOCK_METHOD1(workerGlobalScopeStarted, void(WorkerGlobalScope*)); |
| 46 MOCK_METHOD0(workerGlobalScopeClosed, void()); |
| 47 MOCK_METHOD0(workerThreadTerminated, void()); |
| 48 MOCK_METHOD0(willDestroyWorkerGlobalScope, void()); |
| 49 }; |
| 50 |
| 51 class FakeWorkerGlobalScope : public WorkerGlobalScope { |
| 52 public: |
| 53 typedef WorkerGlobalScope Base; |
| 54 |
| 55 FakeWorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread
* thread, const SecurityOrigin* starterOrigin, PassOwnPtrWillBeRawPtr<WorkerClie
nts> workerClients) |
| 56 : WorkerGlobalScope(url, userAgent, thread, monotonicallyIncreasingTime(
), starterOrigin, workerClients) |
| 57 { |
| 58 } |
| 59 |
| 60 ~FakeWorkerGlobalScope() override |
| 61 { |
| 62 } |
| 63 |
| 64 virtual bool isSharedWorkerGlobalScope() const override { return true; } |
| 65 |
| 66 // EventTarget |
| 67 virtual const AtomicString& interfaceName() const override |
| 68 { |
| 69 return EventTargetNames::SharedWorkerGlobalScope; |
| 70 } |
| 71 |
| 72 virtual void logExceptionToConsole(const String&, int , const String&, int,
int, PassRefPtrWillBeRawPtr<ScriptCallStack>) override |
| 73 { |
| 74 } |
| 75 |
| 76 // Setters/Getters for attributes in SharedWorkerGlobalScope.idl |
| 77 DEFINE_ATTRIBUTE_EVENT_LISTENER(connect); |
| 78 String name() const { return "FakeWorkerGlobalScope"; } |
| 79 |
| 80 DECLARE_VIRTUAL_TRACE(); |
| 81 }; |
| 82 |
| 83 DEFINE_TRACE(FakeWorkerGlobalScope) |
| 84 { |
| 85 WorkerGlobalScope::trace(visitor); |
| 86 } |
| 87 |
| 88 class WorkerThreadForTest : public WorkerThread { |
| 89 public: |
| 90 WorkerThreadForTest( |
| 91 WorkerLoaderProxy* mockWorkerLoaderProxy, |
| 92 WorkerReportingProxy& mockWorkerReportingProxy, |
| 93 PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> workerThreadStartupData) |
| 94 : WorkerThread(mockWorkerLoaderProxy, mockWorkerReportingProxy, workerTh
readStartupData) |
| 95 { |
| 96 } |
| 97 |
| 98 ~WorkerThreadForTest() override { } |
| 99 |
| 100 using WorkerThread::threadForTesting; |
| 101 |
| 102 MOCK_METHOD1(doIdleGc, bool(double deadlineSeconds)); |
| 103 |
| 104 PassRefPtrWillBeRawPtr<WorkerGlobalScope> createWorkerGlobalScope(PassOwnPtr
<WorkerThreadStartupData> startupData) override |
| 105 { |
| 106 return adoptRefWillBeNoop(new FakeWorkerGlobalScope(startupData->m_scrip
tURL, startupData->m_userAgent, this, startupData->m_starterOrigin, startupData-
>m_workerClients.release())); |
| 107 } |
| 108 }; |
| 109 |
| 110 class WakeupTask : public WebThread::Task { |
| 111 public: |
| 112 WakeupTask() { } |
| 113 |
| 114 ~WakeupTask() override { } |
| 115 |
| 116 void run() override { } |
| 117 }; |
| 118 |
| 119 class PostDelayedWakeupTask : public WebThread::Task { |
| 120 public: |
| 121 PostDelayedWakeupTask(WebThreadSupportingGC* gc, long long delay) : m_gc(gc)
, m_delay(delay) { } |
| 122 |
| 123 ~PostDelayedWakeupTask() override { } |
| 124 |
| 125 void run() override |
| 126 { |
| 127 m_gc->postDelayedTask(FROM_HERE, new WakeupTask(), m_delay); |
| 128 } |
| 129 |
| 130 WebThreadSupportingGC* m_gc; |
| 131 long long m_delay; |
| 132 }; |
| 133 |
| 134 } // namespace |
| 135 |
| 136 class WorkerThreadTest : public testing::Test { |
| 137 public: |
| 138 void SetUp() override |
| 139 { |
| 140 m_mockWorkerLoaderProxy = new MockWorkerLoaderProxy(); |
| 141 m_mockWorkerReportingProxy = adoptPtr(new MockWorkerReportingProxy()); |
| 142 m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http://
fake.url/")); |
| 143 m_workerThread = adoptRef(new WorkerThreadForTest( |
| 144 m_mockWorkerLoaderProxy.get(), |
| 145 *m_mockWorkerReportingProxy, |
| 146 WorkerThreadStartupData::create( |
| 147 KURL(ParsedURLString, "http://fake.url/"), |
| 148 "fake user agent", |
| 149 "//fake source code", |
| 150 nullptr, |
| 151 DontPauseWorkerGlobalScopeOnStart, |
| 152 "contentSecurityPolicy", |
| 153 ContentSecurityPolicyHeaderTypeReport, |
| 154 m_securityOrigin.get(), |
| 155 WorkerClients::create(), |
| 156 V8CacheOptionsDefault))); |
| 157 ExpectWorkerLifetimeReportingCalls(); |
| 158 } |
| 159 |
| 160 void PostWakeUpTask(long long waitMs) |
| 161 { |
| 162 WebThreadSupportingGC* thread = m_workerThread->threadForTesting(); |
| 163 |
| 164 // The idle task will get posted on an after wake up queue, so we need a
nother task |
| 165 // posted at the right time to wake the system up. We don't know the ri
ght delay here |
| 166 // since the thread can take a variable length of time to be responsive,
however this |
| 167 // isn't a problem when posting a delayed task from within a task on the
worker thread. |
| 168 thread->postTask(FROM_HERE, new PostDelayedWakeupTask(thread, waitMs)); |
| 169 } |
| 170 |
| 171 protected: |
| 172 void ExpectWorkerLifetimeReportingCalls() |
| 173 { |
| 174 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti
mes(1); |
| 175 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(true)).
Times(1); |
| 176 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times
(1); |
| 177 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope())
.Times(1); |
| 178 } |
| 179 |
| 180 RefPtr<SecurityOrigin> m_securityOrigin; |
| 181 RefPtr<MockWorkerLoaderProxy> m_mockWorkerLoaderProxy; |
| 182 OwnPtr<MockWorkerReportingProxy> m_mockWorkerReportingProxy; |
| 183 RefPtr<WorkerThreadForTest> m_workerThread; |
| 184 }; |
| 185 |
| 186 TEST_F(WorkerThreadTest, GcOccursWhileIdle) |
| 187 { |
| 188 bool gcDone = false; |
| 189 |
| 190 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke( |
| 191 [&gcDone](double) |
| 192 { |
| 193 gcDone = true; |
| 194 return false; |
| 195 })); |
| 196 |
| 197 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1); |
| 198 |
| 199 m_workerThread->start(); |
| 200 |
| 201 PostWakeUpTask(310ul); |
| 202 |
| 203 while (!gcDone) |
| 204 Platform::current()->yieldCurrentThread(); |
| 205 |
| 206 m_workerThread->terminateAndWait(); |
| 207 }; |
| 208 |
| 209 class RepeatingTask : public WebThread::Task { |
| 210 public: |
| 211 RepeatingTask(WebThreadSupportingGC* thread, int* taskCount) |
| 212 : m_thread(thread) |
| 213 , m_taskCount(taskCount) |
| 214 { } |
| 215 |
| 216 ~RepeatingTask() override { } |
| 217 |
| 218 void run() override |
| 219 { |
| 220 (*m_taskCount)++; |
| 221 m_thread->postDelayedTask(FROM_HERE, new RepeatingTask(m_thread, m_taskC
ount), 50ul); |
| 222 m_thread->postTask(FROM_HERE, new WakeupTask()); |
| 223 } |
| 224 |
| 225 private: |
| 226 WebThreadSupportingGC* m_thread; // NOT OWNED |
| 227 int* m_taskCount; |
| 228 }; |
| 229 |
| 230 TEST_F(WorkerThreadTest, GcDoesNotOccurIfGapBetweenDelayedTasksIsTooSmall) |
| 231 { |
| 232 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(0); |
| 233 |
| 234 m_workerThread->start(); |
| 235 |
| 236 WebThreadSupportingGC* thread = m_workerThread->threadForTesting(); |
| 237 |
| 238 // Post a repeating task that should prevent any GC from happening. |
| 239 int taskCount = 0; |
| 240 thread->postTask(FROM_HERE, new RepeatingTask(thread, &taskCount)); |
| 241 |
| 242 while (taskCount < 10) |
| 243 Platform::current()->yieldCurrentThread(); |
| 244 |
| 245 // Make sure doIdleGc has not been called by this stage. |
| 246 Mock::VerifyAndClearExpectations(m_workerThread.get()); |
| 247 m_workerThread->terminateAndWait(); |
| 248 } |
| 249 |
| 250 } // namespace blink |
OLD | NEW |