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

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: Now uses the WebThread's WebScheduler 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 <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("Test Thread", mockWorkerLoaderProxy, mockWorkerReporting Proxy, workerThreadStartupData)
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
120 class PostDelayedWakeupTask : public WebThread::Task {
121 public:
122 PostDelayedWakeupTask(WebThreadSupportingGC* gc, long long delay) : m_gc(gc) , m_delay(delay) { }
123
124 ~PostDelayedWakeupTask() override { }
125
126 void run() override
127 {
128 m_gc->postDelayedTask(FROM_HERE, new WakeupTask(), m_delay);
129 }
130
131 WebThreadSupportingGC* m_gc;
132 long long m_delay;
133 };
134
135 } // namespace
136
137 class WorkerThreadTest : public testing::Test {
138 public:
139 void SetUp() override
140 {
141 m_mockWorkerLoaderProxy = new MockWorkerLoaderProxy();
142 m_mockWorkerReportingProxy = adoptPtr(new MockWorkerReportingProxy());
143 m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http:// fake.url/"));
144 m_workerThread = adoptRef(new WorkerThreadForTest(
145 m_mockWorkerLoaderProxy.get(),
146 *m_mockWorkerReportingProxy,
147 WorkerThreadStartupData::create(
148 KURL(ParsedURLString, "http://fake.url/"),
149 "fake user agent",
150 "//fake source code",
151 nullptr,
152 DontPauseWorkerGlobalScopeOnStart,
153 "contentSecurityPolicy",
154 ContentSecurityPolicyHeaderTypeReport,
155 m_securityOrigin.get(),
156 WorkerClients::create(),
157 V8CacheOptionsDefault)));
158 ExpectWorkerLifetimeReportingCalls();
159 }
160
161 void PostWakeUpTask(long long waitMs)
162 {
163 WebThreadSupportingGC* thread = m_workerThread->threadForTesting();
164
165 // The idle task will get posted on an after wake up queue, so we need a nother task
166 // posted at the right time to wake the system up. We don't know the ri ght delay here
167 // since the thread can take a variable length of time to be responsive, however this
168 // isn't a problem when posting a delayed task from within a task on the worker thread.
169 thread->postTask(FROM_HERE, new PostDelayedWakeupTask(thread, waitMs));
170 }
171
172 protected:
173 void ExpectWorkerLifetimeReportingCalls()
174 {
175 EXPECT_CALL(*m_mockWorkerReportingProxy, workerGlobalScopeStarted(_)).Ti mes(1);
176 EXPECT_CALL(*m_mockWorkerReportingProxy, didEvaluateWorkerScript(true)). Times(1);
177 EXPECT_CALL(*m_mockWorkerReportingProxy, workerThreadTerminated()).Times (1);
178 EXPECT_CALL(*m_mockWorkerReportingProxy, willDestroyWorkerGlobalScope()) .Times(1);
179 }
180
181 RefPtr<SecurityOrigin> m_securityOrigin;
182 RefPtr<MockWorkerLoaderProxy> m_mockWorkerLoaderProxy;
183 OwnPtr<MockWorkerReportingProxy> m_mockWorkerReportingProxy;
184 RefPtr<WorkerThreadForTest> m_workerThread;
185 };
186
187 TEST_F(WorkerThreadTest, GcOccursWhileIdle)
188 {
189 bool gcDone = false;
Sami 2015/04/16 14:23:38 Should this be some kind of thread safe primitive
alex clarke (OOO till 29th) 2015/04/16 17:20:01 I added some mutexes and a ThreadCondition
190
191 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
192 [&gcDone](double)
193 {
194 gcDone = true;
195 return false;
196 }));
197
198 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
199
200 m_workerThread->start();
201
202 PostWakeUpTask(310ul); // 10ms after the quiescent period ends.
203
204 while (!gcDone)
205 Platform::current()->yieldCurrentThread();
206
207 m_workerThread->terminateAndWait();
208 };
209
210 class RepeatingTask : public WebThread::Task {
211 public:
212 RepeatingTask(WebThreadSupportingGC* thread, int* taskCount)
213 : m_thread(thread)
214 , m_taskCount(taskCount)
215 { }
216
217 ~RepeatingTask() override { }
218
219 void run() override
220 {
221 (*m_taskCount)++;
222 m_thread->postDelayedTask(FROM_HERE, new RepeatingTask(m_thread, m_taskC ount), 50ul);
223 m_thread->postTask(FROM_HERE, new WakeupTask());
224 }
225
226 private:
227 WebThreadSupportingGC* m_thread; // NOT OWNED
228 int* m_taskCount;
229 };
230
231 TEST_F(WorkerThreadTest, GcDoesNotOccurIfGapBetweenDelayedTasksIsTooSmall)
232 {
233 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(0);
234
235 m_workerThread->start();
236
237 WebThreadSupportingGC* thread = m_workerThread->threadForTesting();
238
239 // Post a repeating task that should prevent any GC from happening.
240 int taskCount = 0;
241 thread->postTask(FROM_HERE, new RepeatingTask(thread, &taskCount));
242
243 while (taskCount < 10)
Sami 2015/04/16 14:23:38 Is this thread safe?
alex clarke (OOO till 29th) 2015/04/16 17:20:01 Done.
244 Platform::current()->yieldCurrentThread();
245
246 // Make sure doIdleGc has not been called by this stage.
247 Mock::VerifyAndClearExpectations(m_workerThread.get());
248 m_workerThread->terminateAndWait();
249 }
250
251 TEST_F(WorkerThreadTest, LongGcDeadline)
252 {
253 bool gcDone = false;
254 double deadlineLength = 0;
255
256 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
257 [&gcDone, &deadlineLength](double deadline)
258 {
259 deadlineLength = deadline -Platform::current()->monotonicallyIncreas ingTime();
260 gcDone = true;
261 return false;
262 }));
263
264 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
265
266 m_workerThread->start();
267
268 PostWakeUpTask(310ul);
269
270 while (!gcDone)
271 Platform::current()->yieldCurrentThread();
272
273 // The deadline should be close to 1s in duration if there are no tasks that need to run soon.
274 EXPECT_GT(deadlineLength, 0.9);
275
276 m_workerThread->terminateAndWait();
277 }
278
279 TEST_F(WorkerThreadTest, ShortGcDeadline)
280 {
281 bool gcDone = false;
282 double deadlineLength = 0;
283
284 ON_CALL(*m_workerThread, doIdleGc(_)).WillByDefault(Invoke(
285 [&gcDone, &deadlineLength](double deadline)
286 {
287 deadlineLength = deadline -Platform::current()->monotonicallyIncreas ingTime();
288 gcDone = true;
289 return false;
290 }));
291
292 EXPECT_CALL(*m_workerThread, doIdleGc(_)).Times(1);
293
294 m_workerThread->start();
295
296 PostWakeUpTask(310ul);
297 PostWakeUpTask(650ul); // Task that run shortly after the idle period starts .
298
299 while (!gcDone)
300 Platform::current()->yieldCurrentThread();
301
302 // The deadlin should be short if there's a task that needs to run shortly a fter the idle period starts.
303 EXPECT_LT(deadlineLength, 0.05);
304
305 m_workerThread->terminateAndWait();
306 }
307
308 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698