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

Side by Side Diff: Source/core/workers/WorkerThreadTest.cpp

Issue 956333002: Refactor TimeBase to post tasks. Workers to use real Idle tasks. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Some of Ross's suggestions Created 5 years, 8 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 unified diff | Download patch
OLDNEW
(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 "wtf/ThreadingPrimitives.h"
16 #include <gmock/gmock.h>
17 #include <gtest/gtest.h>
18
19 using testing::_;
20 using testing::Invoke;
21 using testing::Return;
22 using testing::Mock;
23
24 namespace blink {
25
26 namespace {
27 class MockWorkerLoaderProxy : public WorkerLoaderProxy {
28 public:
29 MockWorkerLoaderProxy() : WorkerLoaderProxy(nullptr) { }
30 ~MockWorkerLoaderProxy() override { }
31
32 MOCK_METHOD1(postTaskToLoader, void(PassOwnPtr<ExecutionContextTask>));
33 MOCK_METHOD1(postTaskToWorkerGlobalScope, bool(PassOwnPtr<ExecutionContextTa sk>));
34 };
35
36 class MockWorkerReportingProxy : public WorkerReportingProxy {
37 public:
38 MockWorkerReportingProxy() { }
39 ~MockWorkerReportingProxy() override { }
40
41 MOCK_METHOD5(reportException, void(const String& errorMessage, int lineNumbe r, int columnNumber, const String& sourceURL, int exceptionId));
42 MOCK_METHOD1(reportConsoleMessage, void(PassRefPtrWillBeRawPtr<ConsoleMessag e>));
43 MOCK_METHOD1(postMessageToPageInspector, void(const String&));
44 MOCK_METHOD0(postWorkerConsoleAgentEnabled, void());
45 MOCK_METHOD1(didEvaluateWorkerScript, void(bool success));
46 MOCK_METHOD1(workerGlobalScopeStarted, void(WorkerGlobalScope*));
47 MOCK_METHOD0(workerGlobalScopeClosed, void());
48 MOCK_METHOD0(workerThreadTerminated, void());
49 MOCK_METHOD0(willDestroyWorkerGlobalScope, void());
50 };
51
52 class FakeWorkerGlobalScope : public WorkerGlobalScope {
53 public:
54 typedef WorkerGlobalScope Base;
55
56 FakeWorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread * thread, const SecurityOrigin* starterOrigin, PassOwnPtrWillBeRawPtr<WorkerClie nts> workerClients)
57 : WorkerGlobalScope(url, userAgent, thread, monotonicallyIncreasingTime( ), starterOrigin, workerClients)
58 {
59 }
60
61 ~FakeWorkerGlobalScope() override
62 {
63 }
64
65 virtual bool isSharedWorkerGlobalScope() const override { return true; }
66
67 // EventTarget
68 virtual const AtomicString& interfaceName() const override
69 {
70 return EventTargetNames::SharedWorkerGlobalScope;
71 }
72
73 virtual void logExceptionToConsole(const String&, int , const String&, int, int, PassRefPtrWillBeRawPtr<ScriptCallStack>) override
74 {
75 }
76
77 // Setters/Getters for attributes in SharedWorkerGlobalScope.idl
78 DEFINE_ATTRIBUTE_EVENT_LISTENER(connect);
79 String name() const { return "FakeWorkerGlobalScope"; }
80
81 DECLARE_VIRTUAL_TRACE();
82 };
83
84 DEFINE_TRACE(FakeWorkerGlobalScope)
85 {
86 WorkerGlobalScope::trace(visitor);
87 }
88
89 class WorkerThreadForTest : public WorkerThread {
90 public:
91 WorkerThreadForTest(
92 WorkerLoaderProxy* mockWorkerLoaderProxy,
93 WorkerReportingProxy& mockWorkerReportingProxy,
94 PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> workerThreadStartupData)
95 : WorkerThread("Test Thread", mockWorkerLoaderProxy, mockWorkerReporting Proxy, workerThreadStartupData)
96 {
97 }
98
99 ~WorkerThreadForTest() override { }
100
101 using WorkerThread::threadForTesting;
102
103 MOCK_METHOD1(doIdleGc, bool(double deadlineSeconds));
104
105 PassRefPtrWillBeRawPtr<WorkerGlobalScope> createWorkerGlobalScope(PassOwnPtr <WorkerThreadStartupData> startupData) override
106 {
107 return adoptRefWillBeNoop(new FakeWorkerGlobalScope(startupData->m_scrip tURL, startupData->m_userAgent, this, startupData->m_starterOrigin, startupData- >m_workerClients.release()));
108 }
109 };
110
111 class WakeupTask : public WebThread::Task {
112 public:
113 WakeupTask() { }
114
115 ~WakeupTask() override { }
116
117 void run() override { }
118 };
119
120
121 class PostDelayedWakeupTask : public WebThread::Task {
122 public:
123 PostDelayedWakeupTask(WebThreadSupportingGC* gc, long long delay) : m_gc(gc) , m_delay(delay) { }
124
125 ~PostDelayedWakeupTask() override { }
126
127 void run() override
128 {
129 m_gc->postDelayedTask(FROM_HERE, new WakeupTask(), m_delay);
130 }
131
132 WebThreadSupportingGC* m_gc;
133 long long m_delay;
134 };
135
136 } // namespace
137
138 class WorkerThreadTest : public testing::Test {
139 public:
140 void SetUp() override
141 {
142 m_mockWorkerLoaderProxy = new MockWorkerLoaderProxy();
143 m_mockWorkerReportingProxy = adoptPtr(new MockWorkerReportingProxy());
144 m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http:// fake.url/"));
145 m_workerThread = adoptRef(new WorkerThreadForTest(
146 m_mockWorkerLoaderProxy.get(),
147 *m_mockWorkerReportingProxy,
148 WorkerThreadStartupData::create(
149 KURL(ParsedURLString, "http://fake.url/"),
150 "fake user agent",
151 "//fake source code",
152 nullptr,
153 DontPauseWorkerGlobalScopeOnStart,
154 "contentSecurityPolicy",
155 ContentSecurityPolicyHeaderTypeReport,
156 m_securityOrigin.get(),
157 WorkerClients::create(),
158 V8CacheOptionsDefault)));
159 ExpectWorkerLifetimeReportingCalls();
160 }
161
162 void PostWakeUpTask(long long waitMs)
163 {
164 WebThreadSupportingGC* thread = m_workerThread->threadForTesting();
165
166 // The idle task will get posted on an after wake up queue, so we need a nother task
167 // posted at the right time to wake the system up. We don't know the ri ght delay here
168 // since the thread can take a variable length of time to be responsive, however this
169 // isn't a problem when posting a delayed task from within a task on the worker thread.
170 thread->postTask(FROM_HERE, new PostDelayedWakeupTask(thread, waitMs));
171 }
172
173 protected:
174 void ExpectWorkerLifetimeReportingCalls()
175 {
176 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti mes(1);
177 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(true)). Times(1);
178 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times (1);
179 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) .Times(1);
180 }
181
182 RefPtr<SecurityOrigin> m_securityOrigin;
183 RefPtr<MockWorkerLoaderProxy> m_mockWorkerLoaderProxy;
184 OwnPtr<MockWorkerReportingProxy> m_mockWorkerReportingProxy;
185 RefPtr<WorkerThreadForTest> m_workerThread;
186 };
187
188 TEST_F(WorkerThreadTest, GcOccursWhileIdle)
189 {
190 ThreadCondition gcDone;
191 Mutex mutex;
192
193 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
194 [&gcDone, &mutex](double)
195 {
196 WTF::Locker<Mutex> lock(mutex);
197 gcDone.signal();
198 return false;
199 }));
200
201 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
202
203 m_workerThread->start();
204
205 PostWakeUpTask(310ul); // 10ms after the quiescent period ends.
206
207 {
208 WTF::Locker<Mutex> lock(mutex);
209 gcDone.wait(mutex);
210 }
211
212 m_workerThread->terminateAndWait();
213 };
214
215 class RepeatingTask : public WebThread::Task {
216 public:
217 RepeatingTask(WebThreadSupportingGC* thread, ThreadCondition* completion, Mu tex* mutex, int taskCount)
218 : m_thread(thread)
219 , m_completion(completion)
220 , m_mutex(mutex)
221 , m_taskCount(taskCount)
rmcilroy 2015/04/17 16:33:22 Could we make the public constructor not take 'tas
rmcilroy 2015/04/20 20:56:50 Still to do?
222 { }
223
224 ~RepeatingTask() override { }
225
226 void run() override
227 {
228 m_taskCount++;
229 if (m_taskCount == 10) {
230 WTF::Locker<Mutex> lock(*m_mutex);
231 m_completion->signal();
232 }
233
234 m_thread->postDelayedTask(
235 FROM_HERE, new RepeatingTask(m_thread, m_completion, m_mutex, m_task Count), 50ul);
236 m_thread->postTask(FROM_HERE, new WakeupTask());
237
238 }
239
240 private:
241 WebThreadSupportingGC* m_thread; // NOT OWNED
242 ThreadCondition* m_completion;
243 Mutex* m_mutex;
244 int m_taskCount;
245 };
246
247 TEST_F(WorkerThreadTest, GcDoesNotOccurIfGapBetweenDelayedTasksIsTooSmall)
248 {
249 ThreadCondition completion;
250 Mutex mutex;
251
252 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(0);
253
254 m_workerThread->start();
255
256 WebThreadSupportingGC* thread = m_workerThread->threadForTesting();
257
258 // Post a repeating task that should prevent any GC from happening.
259 thread->postTask(FROM_HERE, new RepeatingTask(thread, &completion, &mutex, 0 ));
260
261 {
262 WTF::Locker<Mutex> lock(mutex);
263 completion.wait(mutex);
264 }
265
266 // Make sure doIdleGc has not been called by this stage.
267 Mock::VerifyAndClearExpectations(m_workerThread.get());
268 m_workerThread->terminateAndWait();
269 }
270
271 TEST_F(WorkerThreadTest, LongGcDeadline)
272 {
273 ThreadCondition gcDone;
274 Mutex mutex;
275 double deadlineLength = 0;
276
277 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
278 [&gcDone, &mutex, &deadlineLength](double deadline)
279 {
280 WTF::Locker<Mutex> lock(mutex);
281 gcDone.signal();
282 deadlineLength = deadline -Platform::current()->monotonicallyIncreas ingTime();
283 return false;
284 }));
285
286 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
287
288 m_workerThread->start();
289
290 PostWakeUpTask(310ul);
291
292 {
293 WTF::Locker<Mutex> lock(mutex);
294 gcDone.wait(mutex);
295
296 // The deadline should be close to 1s in duration if there are no tasks that need to run soon.
297 EXPECT_GT(deadlineLength, 0.9);
298 }
299
300 m_workerThread->terminateAndWait();
301 }
302
303 TEST_F(WorkerThreadTest, ShortGcDeadline)
rmcilroy 2015/04/17 16:33:22 Could we add one more test which ensures that if t
alex clarke (OOO till 29th) 2015/04/20 10:06:54 Done but I realized this throws up an interesting
rmcilroy 2015/04/20 20:56:50 CanExceedIdleDeadlineIfRequired should only return
304 {
305 ThreadCondition gcDone;
306 Mutex mutex;
307 double deadlineLength = 0;
308
309 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
310 [&gcDone, &mutex, &deadlineLength](double deadline)
311 {
312 WTF::Locker<Mutex> lock(mutex);
313 gcDone.signal();
314 deadlineLength = deadline -Platform::current()->monotonicallyIncreas ingTime();
315 return false;
316 }));
317
318 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
319
320 m_workerThread->start();
321
322 PostWakeUpTask(310ul);
323 PostWakeUpTask(650ul); // Task that run shortly after the idle period starts .
324
325 {
326 WTF::Locker<Mutex> lock(mutex);
327 gcDone.wait(mutex);
328
329 // The deadlin should be short if there's a task that needs to run short ly after the idle period starts.
rmcilroy 2015/04/17 16:33:22 /s/deadlin/deadline
alex clarke (OOO till 29th) 2015/04/20 10:06:54 Done.
330 EXPECT_LT(deadlineLength, 0.05);
331 }
332
333 m_workerThread->terminateAndWait();
334 }
335
336 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698