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/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 | |
OLD | NEW |