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

Side by Side Diff: Source/core/dom/ScriptRunnerTest.cpp

Issue 936493003: Revert of Teach ScriptRunner how to yield and post on loading task queue (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 10 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
« no previous file with comments | « Source/core/dom/ScriptRunner.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/dom/ScriptRunner.h"
7
8 #include "core/dom/Document.h"
9 #include "core/dom/ScriptLoader.h"
10 #include "platform/heap/Handle.h"
11 #include "platform/scheduler/Scheduler.h"
12 #include "public/platform/Platform.h"
13 #include "wtf/PassOwnPtr.h"
14 #include <gmock/gmock.h>
15 #include <gtest/gtest.h>
16
17 using ::testing::Invoke;
18 using ::testing::ElementsAre;
19 using ::testing::Return;
20
21 namespace blink {
22
23 class MockScriptLoader: public ScriptLoader {
24 public:
25 explicit MockScriptLoader(Element* element) : ScriptLoader(element, false, f alse) { }
26
27 ~MockScriptLoader() override { }
28
29 MOCK_METHOD0(execute, void());
30 MOCK_CONST_METHOD0(isReady, bool());
31 };
32
33 class MockPlatform : public Platform, private WebScheduler {
34 public:
35 MockPlatform() : m_shouldYield(false), m_shouldYieldEveryOtherTime(false) { }
36
37 WebScheduler* scheduler() override
38 {
39 return this;
40 }
41
42 void postLoadingTask(const WebTraceLocation&, WebThread::Task* task) overrid e
43 {
44 m_tasks.append(adoptPtr(task));
45 }
46
47 void cryptographicallyRandomValues(unsigned char* buffer, size_t length) ove rride { }
48
49 void runSingleTask()
50 {
51 if (m_tasks.isEmpty())
52 return;
53 m_tasks.takeFirst()->run();
54 }
55
56 void runAllTasks()
57 {
58 while (!m_tasks.isEmpty())
59 m_tasks.takeFirst()->run();
60 }
61
62 bool shouldYieldForHighPriorityWork() override
63 {
64 if (m_shouldYieldEveryOtherTime)
65 m_shouldYield = !m_shouldYield;
66 return m_shouldYield;
67 }
68
69 void setShouldYield(bool shouldYield)
70 {
71 m_shouldYield = shouldYield;
72 }
73
74 // NOTE if we yield 100% of the time, nothing will get run.
75 void setShouldYieldEveryOtherTime(bool shouldYieldEveryOtherTime)
76 {
77 m_shouldYieldEveryOtherTime = shouldYieldEveryOtherTime;
78 }
79
80 private:
81 Deque<OwnPtr<WebThread::Task>> m_tasks;
82 bool m_shouldYield;
83 bool m_shouldYieldEveryOtherTime;
84 };
85
86 class ScriptRunnerTest : public testing::Test {
87 public:
88 void SetUp() override
89 {
90 m_document = Document::create();
91 m_element = m_document->createElement("foo", ASSERT_NO_EXCEPTION);
92
93 m_scriptRunner = ScriptRunner::create(m_document.get());
94 m_oldPlatform = Platform::current();
95 Platform::initialize(&m_platform);
96 m_platform.setShouldYield(false);
97 m_platform.setShouldYieldEveryOtherTime(false);
98 }
99
100 void TearDown() override
101 {
102 m_scriptRunner.release();
103 Scheduler::shutdown();
104 Platform::initialize(m_oldPlatform);
105 }
106
107 RefPtrWillBePersistent<Document> m_document;
108 RefPtrWillBePersistent<Element> m_element;
109 OwnPtrWillBePersistent<ScriptRunner> m_scriptRunner;
110 std::vector<int> m_order; // gmock matchers don't work nicely with WTF::Vect or
111 MockPlatform m_platform;
112 Platform* m_oldPlatform;
113 };
114
115 TEST_F(ScriptRunnerTest, QueueSingleScript_Async)
116 {
117 MockScriptLoader scriptLoader(m_element.get());
118 m_scriptRunner->queueScriptForExecution(&scriptLoader, ScriptRunner::ASYNC_E XECUTION);
119 m_scriptRunner->notifyScriptReady(&scriptLoader, ScriptRunner::ASYNC_EXECUTI ON);
120
121 EXPECT_CALL(scriptLoader, execute());
122 m_platform.runAllTasks();
123 }
124
125 TEST_F(ScriptRunnerTest, QueueSingleScript_InOrder)
126 {
127 MockScriptLoader scriptLoader(m_element.get());
128 m_scriptRunner->queueScriptForExecution(&scriptLoader, ScriptRunner::IN_ORDE R_EXECUTION);
129 m_scriptRunner->resume();
130
131 EXPECT_CALL(scriptLoader, isReady()).WillOnce(Return(true));
132 EXPECT_CALL(scriptLoader, execute());
133 m_platform.runAllTasks();
134 }
135
136 TEST_F(ScriptRunnerTest, QueueMultipleScripts_InOrder)
137 {
138 MockScriptLoader scriptLoader1(m_element.get());
139 MockScriptLoader scriptLoader2(m_element.get());
140 MockScriptLoader scriptLoader3(m_element.get());
141
142 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
143 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN_ORD ER_EXECUTION);
144 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN_ORD ER_EXECUTION);
145
146 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
147 m_order.push_back(1);
148 }));
149 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
150 m_order.push_back(2);
151 }));
152 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
153 m_order.push_back(3);
154 }));
155
156 // Make the scripts become ready in reverse order.
157 bool isReady[] = { false, false, false };
158 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Invoke([&isReady] {
159 return isReady[0];
160 }));
161 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Invoke([&isReady] {
162 return isReady[1];
163 }));
164 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Invoke([&isReady] {
165 return isReady[2];
166 }));
167
168 for (int i = 2; i >= 0; i--) {
169 isReady[i] = true;
170 m_scriptRunner->resume();
171 m_platform.runAllTasks();
172 }
173
174 // But ensure the scripts were run in the expected order.
175 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
176 }
177
178 TEST_F(ScriptRunnerTest, QueueMixedScripts)
179 {
180 MockScriptLoader scriptLoader1(m_element.get());
181 MockScriptLoader scriptLoader2(m_element.get());
182 MockScriptLoader scriptLoader3(m_element.get());
183 MockScriptLoader scriptLoader4(m_element.get());
184 MockScriptLoader scriptLoader5(m_element.get());
185
186 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Return(true));
187 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
188 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
189
190 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
191 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN_ORD ER_EXECUTION);
192 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN_ORD ER_EXECUTION);
193 m_scriptRunner->queueScriptForExecution(&scriptLoader4, ScriptRunner::ASYNC_ EXECUTION);
194 m_scriptRunner->queueScriptForExecution(&scriptLoader5, ScriptRunner::ASYNC_ EXECUTION);
195
196 m_scriptRunner->notifyScriptReady(&scriptLoader4, ScriptRunner::ASYNC_EXECUT ION);
197 m_scriptRunner->notifyScriptReady(&scriptLoader5, ScriptRunner::ASYNC_EXECUT ION);
198
199 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
200 m_order.push_back(1);
201 }));
202 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
203 m_order.push_back(2);
204 }));
205 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
206 m_order.push_back(3);
207 }));
208 EXPECT_CALL(scriptLoader4, execute()).WillOnce(Invoke([this] {
209 m_order.push_back(4);
210 }));
211 EXPECT_CALL(scriptLoader5, execute()).WillOnce(Invoke([this] {
212 m_order.push_back(5);
213 }));
214
215 m_platform.runAllTasks();
216
217 // Make sure the async scripts were run before the in-order ones.
218 EXPECT_THAT(m_order, ElementsAre(4, 5, 1, 2, 3));
219 }
220
221 TEST_F(ScriptRunnerTest, QueueMixedScripts_YieldAfterEveryExecution)
222 {
223 MockScriptLoader scriptLoader1(m_element.get());
224 MockScriptLoader scriptLoader2(m_element.get());
225 MockScriptLoader scriptLoader3(m_element.get());
226 MockScriptLoader scriptLoader4(m_element.get());
227 MockScriptLoader scriptLoader5(m_element.get());
228
229 m_platform.setShouldYieldEveryOtherTime(true);
230
231 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Return(true));
232 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
233 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
234
235 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
236 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN_ORD ER_EXECUTION);
237 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN_ORD ER_EXECUTION);
238 m_scriptRunner->queueScriptForExecution(&scriptLoader4, ScriptRunner::ASYNC_ EXECUTION);
239 m_scriptRunner->queueScriptForExecution(&scriptLoader5, ScriptRunner::ASYNC_ EXECUTION);
240
241 m_scriptRunner->notifyScriptReady(&scriptLoader4, ScriptRunner::ASYNC_EXECUT ION);
242 m_scriptRunner->notifyScriptReady(&scriptLoader5, ScriptRunner::ASYNC_EXECUT ION);
243
244 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
245 m_order.push_back(1);
246 }));
247 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
248 m_order.push_back(2);
249 }));
250 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
251 m_order.push_back(3);
252 }));
253 EXPECT_CALL(scriptLoader4, execute()).WillOnce(Invoke([this] {
254 m_order.push_back(4);
255 }));
256 EXPECT_CALL(scriptLoader5, execute()).WillOnce(Invoke([this] {
257 m_order.push_back(5);
258 }));
259
260 m_platform.runAllTasks();
261
262 // Make sure the async scripts were run before the in-order ones.
263 EXPECT_THAT(m_order, ElementsAre(4, 5, 1, 2, 3));
264 }
265
266 TEST_F(ScriptRunnerTest, QueueReentrantScript_Async)
267 {
268 MockScriptLoader scriptLoader1(m_element.get());
269 MockScriptLoader scriptLoader2(m_element.get());
270 MockScriptLoader scriptLoader3(m_element.get());
271
272 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::ASYNC_ EXECUTION);
273 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::ASYNC_ EXECUTION);
274 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::ASYNC_ EXECUTION);
275 m_scriptRunner->notifyScriptReady(&scriptLoader1, ScriptRunner::ASYNC_EXECUT ION);
276
277 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([&scriptLoader2, this] {
278 m_order.push_back(1);
279 m_scriptRunner->notifyScriptReady(&scriptLoader2, ScriptRunner::ASYNC_EX ECUTION);
280 }));
281
282 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([&scriptLoader3, this] {
283 m_order.push_back(2);
284 m_scriptRunner->notifyScriptReady(&scriptLoader3, ScriptRunner::ASYNC_EX ECUTION);
285 }));
286
287 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
288 m_order.push_back(3);
289 }));
290
291 // Make sure that re-entrant calls to notifyScriptReady don't cause ScriptRu nner::execute to do
292 // more work than expected.
293 m_platform.runSingleTask();
294 EXPECT_THAT(m_order, ElementsAre(1));
295
296 m_platform.runSingleTask();
297 EXPECT_THAT(m_order, ElementsAre(1, 2));
298
299 m_platform.runSingleTask();
300 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
301 }
302
303 TEST_F(ScriptRunnerTest, QueueReentrantScript_InOrder)
304 {
305 MockScriptLoader scriptLoader1(m_element.get());
306 MockScriptLoader scriptLoader2(m_element.get());
307 MockScriptLoader scriptLoader3(m_element.get());
308
309 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Return(true));
310 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
311 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
312
313 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
314 m_scriptRunner->resume();
315
316 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([&scriptLoader2, this] {
317 m_order.push_back(1);
318 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN _ORDER_EXECUTION);
319 m_scriptRunner->resume();
320 }));
321
322 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([&scriptLoader3, this] {
323 m_order.push_back(2);
324 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN _ORDER_EXECUTION);
325 m_scriptRunner->resume();
326 }));
327
328 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
329 m_order.push_back(3);
330 }));
331
332 // Make sure that re-entrant calls to queueScriptForExecution don't cause Sc riptRunner::execute to do
333 // more work than expected.
334 m_platform.runSingleTask();
335 EXPECT_THAT(m_order, ElementsAre(1));
336
337 m_platform.runSingleTask();
338 EXPECT_THAT(m_order, ElementsAre(1, 2));
339
340 m_platform.runSingleTask();
341 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
342 }
343
344 TEST_F(ScriptRunnerTest, ShouldYield_AsyncScripts)
345 {
346 MockScriptLoader scriptLoader1(m_element.get());
347 MockScriptLoader scriptLoader2(m_element.get());
348 MockScriptLoader scriptLoader3(m_element.get());
349
350 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::ASYNC_ EXECUTION);
351 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::ASYNC_ EXECUTION);
352 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::ASYNC_ EXECUTION);
353 m_scriptRunner->notifyScriptReady(&scriptLoader1, ScriptRunner::ASYNC_EXECUT ION);
354 m_scriptRunner->notifyScriptReady(&scriptLoader2, ScriptRunner::ASYNC_EXECUT ION);
355 m_scriptRunner->notifyScriptReady(&scriptLoader3, ScriptRunner::ASYNC_EXECUT ION);
356
357 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
358 m_order.push_back(1);
359 m_platform.setShouldYield(true);
360 }));
361 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
362 m_order.push_back(2);
363 }));
364 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
365 m_order.push_back(3);
366 }));
367
368 m_platform.runSingleTask();
369 EXPECT_THAT(m_order, ElementsAre(1));
370
371 // Make sure the interrupted tasks are executed next 'tick'.
372 m_platform.setShouldYield(false);
373 m_platform.runSingleTask();
374 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
375 }
376
377 TEST_F(ScriptRunnerTest, ShouldYield_InOrderScripts)
378 {
379 MockScriptLoader scriptLoader1(m_element.get());
380 MockScriptLoader scriptLoader2(m_element.get());
381 MockScriptLoader scriptLoader3(m_element.get());
382
383 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Return(true));
384 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
385 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
386
387 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
388 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN_ORD ER_EXECUTION);
389 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN_ORD ER_EXECUTION);
390 m_scriptRunner->resume();
391
392 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
393 m_order.push_back(1);
394 m_platform.setShouldYield(true);
395 }));
396 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
397 m_order.push_back(2);
398 }));
399 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
400 m_order.push_back(3);
401 }));
402
403 m_platform.runSingleTask();
404 EXPECT_THAT(m_order, ElementsAre(1));
405
406 // Make sure the interrupted tasks are executed next 'tick'.
407 m_platform.setShouldYield(false);
408 m_platform.runSingleTask();
409 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
410 }
411
412 TEST_F(ScriptRunnerTest, ShouldYield_RunsAtLastOneTask_AsyncScripts)
413 {
414 MockScriptLoader scriptLoader1(m_element.get());
415 MockScriptLoader scriptLoader2(m_element.get());
416 MockScriptLoader scriptLoader3(m_element.get());
417
418 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::ASYNC_ EXECUTION);
419 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::ASYNC_ EXECUTION);
420 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::ASYNC_ EXECUTION);
421 m_scriptRunner->notifyScriptReady(&scriptLoader1, ScriptRunner::ASYNC_EXECUT ION);
422 m_scriptRunner->notifyScriptReady(&scriptLoader2, ScriptRunner::ASYNC_EXECUT ION);
423 m_scriptRunner->notifyScriptReady(&scriptLoader3, ScriptRunner::ASYNC_EXECUT ION);
424
425 m_platform.setShouldYield(true);
426 EXPECT_CALL(scriptLoader1, execute()).Times(1);
427 EXPECT_CALL(scriptLoader2, execute()).Times(0);
428 EXPECT_CALL(scriptLoader3, execute()).Times(0);
429
430 m_platform.runSingleTask();
431
432 // We can't safely distruct ScriptRunner with unexecuted MockScriptLoaders ( real ScriptLoader is fine) so drain them.
433 testing::Mock::VerifyAndClear(&scriptLoader2);
434 testing::Mock::VerifyAndClear(&scriptLoader3);
435 m_platform.runAllTasks();
436 }
437
438 TEST_F(ScriptRunnerTest, ShouldYield_RunsAtLastOneTask_InOrderScripts)
439 {
440 MockScriptLoader scriptLoader1(m_element.get());
441 MockScriptLoader scriptLoader2(m_element.get());
442 MockScriptLoader scriptLoader3(m_element.get());
443
444 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Return(true));
445 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
446 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
447
448 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
449 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN_ORD ER_EXECUTION);
450 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN_ORD ER_EXECUTION);
451 m_scriptRunner->resume();
452
453 m_platform.setShouldYield(true);
454 EXPECT_CALL(scriptLoader1, execute()).Times(1);
455 EXPECT_CALL(scriptLoader2, execute()).Times(0);
456 EXPECT_CALL(scriptLoader3, execute()).Times(0);
457
458 m_platform.runSingleTask();
459
460 // We can't safely distruct ScriptRunner with unexecuted MockScriptLoaders ( real ScriptLoader is fine) so drain them.
461 testing::Mock::VerifyAndClear(&scriptLoader2);
462 testing::Mock::VerifyAndClear(&scriptLoader3);
463 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
464 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
465 m_platform.runAllTasks();
466 }
467
468 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/dom/ScriptRunner.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698