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

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

Issue 866273005: Teach ScriptRunner how to yield and post on loading task queue (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Needed to shutdown the sheduler owned by MockPlatform in TearDown() 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
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/scheduler/Scheduler.h"
11 #include "public/platform/Platform.h"
12 #include "wtf/PassOwnPtr.h"
13 #include <gmock/gmock.h>
14 #include <gtest/gtest.h>
15
16 using ::testing::Invoke;
17 using ::testing::ElementsAre;
18 using ::testing::Return;
19
20 namespace blink {
21
22 class MockScriptLoader: public ScriptLoader {
23 public:
24 explicit MockScriptLoader(Element* element) : ScriptLoader(element, false, f alse) { }
25
26 ~MockScriptLoader() override { }
27
28 MOCK_METHOD0(execute, void());
29 MOCK_CONST_METHOD0(isReady, bool());
30 };
31
32 class MockPlatform : public Platform, private WebScheduler {
33 public:
34 MockPlatform() : m_shouldYield(false) { }
35
36 WebScheduler* scheduler() override
37 {
38 return this;
39 }
40
41 void postLoadingTask(const WebTraceLocation&, WebThread::Task* task) overrid e
42 {
43 m_tasks.append(adoptPtr(task));
44 }
45
46 void cryptographicallyRandomValues(unsigned char* buffer, size_t length) ove rride { }
47
48 void runSingleTask()
49 {
50 if (m_tasks.isEmpty())
51 return;
52 m_tasks.takeFirst()->run();
53 }
54
55 void runAllTasks()
56 {
57 while (!m_tasks.isEmpty())
58 m_tasks.takeFirst()->run();
59 }
60
61 bool shouldYieldForHighPriorityWork() override
62 {
63 return m_shouldYield;
64 }
65
66 void setShouldYield(bool shouldYield)
67 {
68 m_shouldYield = shouldYield;
69 }
70
71 private:
72 Deque<OwnPtr<WebThread::Task>> m_tasks;
73 bool m_shouldYield;
74 };
75
76 class ScriptRunnerTest : public testing::Test {
77 public:
78 void SetUp() override
79 {
80 m_document = Document::create();
81 m_element = m_document->createElement("foo", ASSERT_NO_EXCEPTION);
82
83 m_scriptRunner = ScriptRunner::create(m_document.get());
84 m_oldPlatform = Platform::current();
85 Platform::initialize(&m_platform);
86 m_platform.setShouldYield(false);
87 }
88
89 void TearDown() override
90 {
91 Scheduler::shutdown();
92 Platform::initialize(m_oldPlatform);
93 }
94
95 RefPtr<Document> m_document;
96 RefPtr<Element> m_element;
97 OwnPtr<ScriptRunner> m_scriptRunner;
98 std::vector<int> m_order; // gmock matchers don't work nicely with WTF::Vect or
99 MockPlatform m_platform;
100 Platform* m_oldPlatform;
101 };
102
103 TEST_F(ScriptRunnerTest, QueueSingleScript_Async)
104 {
105 MockScriptLoader scriptLoader(m_element.get());
106 m_scriptRunner->queueScriptForExecution(&scriptLoader, ScriptRunner::ASYNC_E XECUTION);
107 m_scriptRunner->notifyScriptReady(&scriptLoader, ScriptRunner::ASYNC_EXECUTI ON);
108
109 EXPECT_CALL(scriptLoader, execute());
110 m_platform.runAllTasks();
111 }
112
113 TEST_F(ScriptRunnerTest, QueueSingleScript_InOrder)
114 {
115 MockScriptLoader scriptLoader(m_element.get());
116 m_scriptRunner->queueScriptForExecution(&scriptLoader, ScriptRunner::IN_ORDE R_EXECUTION);
117 m_scriptRunner->resume();
118
119 EXPECT_CALL(scriptLoader, isReady()).WillOnce(Return(true));
120 EXPECT_CALL(scriptLoader, execute());
121 m_platform.runAllTasks();
122 }
123
124 TEST_F(ScriptRunnerTest, QueueMultipleScripts_InOrder)
125 {
126 MockScriptLoader scriptLoader1(m_element.get());
127 MockScriptLoader scriptLoader2(m_element.get());
128 MockScriptLoader scriptLoader3(m_element.get());
129
130 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
131 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN_ORD ER_EXECUTION);
132 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN_ORD ER_EXECUTION);
133
134 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
135 m_order.push_back(1);
136 }));
137 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
138 m_order.push_back(2);
139 }));
140 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
141 m_order.push_back(3);
142 }));
143
144 // Make the scripts become ready in reverse order.
145 bool isReady[] = { false, false, false };
146 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Invoke([&isReady] {
147 return isReady[0];
148 }));
149 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Invoke([&isReady] {
150 return isReady[1];
151 }));
152 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Invoke([&isReady] {
153 return isReady[2];
154 }));
155
156 for (int i = 2; i >= 0; i--) {
157 isReady[i] = true;
158 m_scriptRunner->resume();
159 m_platform.runAllTasks();
160 }
161
162 // But ensure the scripts were run in the expected order.
163 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
164 }
165
166 TEST_F(ScriptRunnerTest, QueueMixedScripts)
167 {
168 MockScriptLoader scriptLoader1(m_element.get());
169 MockScriptLoader scriptLoader2(m_element.get());
170 MockScriptLoader scriptLoader3(m_element.get());
171 MockScriptLoader scriptLoader4(m_element.get());
172 MockScriptLoader scriptLoader5(m_element.get());
173
174 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Return(true));
175 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
176 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
177
178 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
179 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN_ORD ER_EXECUTION);
180 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN_ORD ER_EXECUTION);
181 m_scriptRunner->queueScriptForExecution(&scriptLoader4, ScriptRunner::ASYNC_ EXECUTION);
182 m_scriptRunner->queueScriptForExecution(&scriptLoader5, ScriptRunner::ASYNC_ EXECUTION);
183
184 m_scriptRunner->notifyScriptReady(&scriptLoader4, ScriptRunner::ASYNC_EXECUT ION);
185 m_scriptRunner->notifyScriptReady(&scriptLoader5, ScriptRunner::ASYNC_EXECUT ION);
186
187 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
188 m_order.push_back(1);
189 }));
190 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
191 m_order.push_back(2);
192 }));
193 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
194 m_order.push_back(3);
195 }));
196 EXPECT_CALL(scriptLoader4, execute()).WillOnce(Invoke([this] {
197 m_order.push_back(4);
198 }));
199 EXPECT_CALL(scriptLoader5, execute()).WillOnce(Invoke([this] {
200 m_order.push_back(5);
201 }));
202
203 m_platform.runAllTasks();
204
205 // Make sure the async scripts where run before the in-order ones.
Sami 2015/02/19 12:52:14 typo: were
alex clarke (OOO till 29th) 2015/02/19 15:11:33 Done.
Sami 2015/02/19 16:25:53 Missed this one?
alex clarke (OOO till 29th) 2015/02/19 16:37:06 Done.
206 EXPECT_THAT(m_order, ElementsAre(4, 5, 1, 2, 3));
207 }
208
209 TEST_F(ScriptRunnerTest, QueueReentrantScript_Async)
210 {
211 MockScriptLoader scriptLoader1(m_element.get());
212 MockScriptLoader scriptLoader2(m_element.get());
213 MockScriptLoader scriptLoader3(m_element.get());
214
215 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::ASYNC_ EXECUTION);
216 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::ASYNC_ EXECUTION);
217 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::ASYNC_ EXECUTION);
218 m_scriptRunner->notifyScriptReady(&scriptLoader1, ScriptRunner::ASYNC_EXECUT ION);
219
220 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([&scriptLoader2, this] {
221 m_order.push_back(1);
222 m_scriptRunner->notifyScriptReady(&scriptLoader2, ScriptRunner::ASYNC_EX ECUTION);
223 }));
224
225 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([&scriptLoader3, this] {
226 m_order.push_back(2);
227 m_scriptRunner->notifyScriptReady(&scriptLoader3, ScriptRunner::ASYNC_EX ECUTION);
228 }));
229
230 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
231 m_order.push_back(3);
232 }));
233
234 // Make sure that re-entrant calls to notifyScriptReady don't cause ScriptRu nner::execute to do
235 // more work than expected.
236 m_platform.runSingleTask();
237 EXPECT_THAT(m_order, ElementsAre(1));
238
239 m_platform.runSingleTask();
240 EXPECT_THAT(m_order, ElementsAre(1, 2));
241
242 m_platform.runSingleTask();
243 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
244 }
245
246 TEST_F(ScriptRunnerTest, QueueReentrantScript_InOrder)
247 {
248 MockScriptLoader scriptLoader1(m_element.get());
249 MockScriptLoader scriptLoader2(m_element.get());
250 MockScriptLoader scriptLoader3(m_element.get());
251
252 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Return(true));
253 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
254 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
255
256 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
257 m_scriptRunner->resume();
258
259 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([&scriptLoader2, this] {
260 m_order.push_back(1);
261 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN _ORDER_EXECUTION);
262 m_scriptRunner->resume();
263 }));
264
265 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([&scriptLoader3, this] {
266 m_order.push_back(2);
267 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN _ORDER_EXECUTION);
268 m_scriptRunner->resume();
269 }));
270
271 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
272 m_order.push_back(3);
273 }));
274
275 // Make sure that re-entrant calls to queueScriptForExecution don't cause Sc riptRunner::execute to do
276 // more work than expected.
277 m_platform.runSingleTask();
278 EXPECT_THAT(m_order, ElementsAre(1));
279
280 m_platform.runSingleTask();
281 EXPECT_THAT(m_order, ElementsAre(1, 2));
282
283 m_platform.runSingleTask();
284 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
285 }
286
287 TEST_F(ScriptRunnerTest, ShouldYield_AsyncScripts)
288 {
289 MockScriptLoader scriptLoader1(m_element.get());
290 MockScriptLoader scriptLoader2(m_element.get());
291 MockScriptLoader scriptLoader3(m_element.get());
292
293 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::ASYNC_ EXECUTION);
294 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::ASYNC_ EXECUTION);
295 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::ASYNC_ EXECUTION);
296 m_scriptRunner->notifyScriptReady(&scriptLoader1, ScriptRunner::ASYNC_EXECUT ION);
297 m_scriptRunner->notifyScriptReady(&scriptLoader2, ScriptRunner::ASYNC_EXECUT ION);
298 m_scriptRunner->notifyScriptReady(&scriptLoader3, ScriptRunner::ASYNC_EXECUT ION);
299
300 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
301 m_order.push_back(1);
302 m_platform.setShouldYield(true);
303 }));
304 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
305 m_order.push_back(2);
306 }));
307 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
308 m_order.push_back(3);
309 }));
310
311 m_platform.runSingleTask(); // Cancelled task due to calling notifyScriptRea dy 3x, does nothing.
312 m_platform.runSingleTask(); // Cancelled task due to calling notifyScriptRea dy 3x, does nothing.
313 m_platform.runSingleTask();
314 EXPECT_THAT(m_order, ElementsAre(1));
315
316 // Make sure the interrupted tasks are executed next 'tick'.
317 m_platform.setShouldYield(false);
318 m_platform.runSingleTask();
319 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
320 }
321
322 TEST_F(ScriptRunnerTest, ShouldYield_InOrderScripts)
323 {
324 MockScriptLoader scriptLoader1(m_element.get());
325 MockScriptLoader scriptLoader2(m_element.get());
326 MockScriptLoader scriptLoader3(m_element.get());
327
328 EXPECT_CALL(scriptLoader1, isReady()).WillRepeatedly(Return(true));
329 EXPECT_CALL(scriptLoader2, isReady()).WillRepeatedly(Return(true));
330 EXPECT_CALL(scriptLoader3, isReady()).WillRepeatedly(Return(true));
331
332 m_scriptRunner->queueScriptForExecution(&scriptLoader1, ScriptRunner::IN_ORD ER_EXECUTION);
333 m_scriptRunner->queueScriptForExecution(&scriptLoader2, ScriptRunner::IN_ORD ER_EXECUTION);
334 m_scriptRunner->queueScriptForExecution(&scriptLoader3, ScriptRunner::IN_ORD ER_EXECUTION);
335 m_scriptRunner->resume();
336
337 EXPECT_CALL(scriptLoader1, execute()).WillOnce(Invoke([this] {
338 m_order.push_back(1);
339 m_platform.setShouldYield(true);
340 }));
341 EXPECT_CALL(scriptLoader2, execute()).WillOnce(Invoke([this] {
342 m_order.push_back(2);
343 }));
344 EXPECT_CALL(scriptLoader3, execute()).WillOnce(Invoke([this] {
345 m_order.push_back(3);
346 }));
347
348 m_platform.runSingleTask();
349 EXPECT_THAT(m_order, ElementsAre(1));
350
351 // Make sure the interrupted tasks are executed next 'tick'.
352 m_platform.setShouldYield(false);
353 m_platform.runSingleTask();
354 EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
355 }
356
357 } // namespace blink
OLDNEW
« Source/core/dom/ScriptRunner.cpp ('K') | « Source/core/dom/ScriptRunner.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698