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 "modules/fetch/ReadableStreamDataConsumerHandle.h" | |
7 | |
8 #include "bindings/core/v8/ScriptState.h" | |
9 #include "bindings/core/v8/V8BindingMacros.h" | |
10 #include "core/dom/Document.h" | |
11 #include "core/testing/DummyPageHolder.h" | |
12 #include "modules/fetch/DataConsumerHandleTestUtil.h" | |
13 #include "platform/heap/Handle.h" | |
14 #include "platform/testing/UnitTestHelpers.h" | |
15 #include "public/platform/WebDataConsumerHandle.h" | |
16 #include "testing/gmock/include/gmock/gmock.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include <v8.h> | |
19 | |
20 // TODO(yhirano): Add cross-thread tests once the handle gets thread-safe. | |
21 namespace blink { | |
22 | |
23 namespace { | |
24 | |
25 using ::testing::InSequence; | |
26 using ::testing::StrictMock; | |
27 using Checkpoint = StrictMock<::testing::MockFunction<void(int)>>; | |
28 using Result = WebDataConsumerHandle::Result; | |
29 const Result kOk = WebDataConsumerHandle::Ok; | |
30 const Result kShouldWait = WebDataConsumerHandle::ShouldWait; | |
31 const Result kUnexpectedError = WebDataConsumerHandle::UnexpectedError; | |
32 const Result kDone = WebDataConsumerHandle::Done; | |
33 using Flags = WebDataConsumerHandle::Flags; | |
34 const Flags kNone = WebDataConsumerHandle::FlagNone; | |
35 | |
36 class MockClient : public GarbageCollectedFinalized<MockClient>, public WebDataC
onsumerHandle::Client { | |
37 public: | |
38 static StrictMock<MockClient>* create() { return new StrictMock<MockClient>(
); } | |
39 MOCK_METHOD0(didGetReadable, void()); | |
40 | |
41 DEFINE_INLINE_TRACE() {} | |
42 | |
43 protected: | |
44 MockClient() = default; | |
45 }; | |
46 | |
47 class ReadableStreamDataConsumerHandleTest : public ::testing::Test { | |
48 public: | |
49 ReadableStreamDataConsumerHandleTest() | |
50 : m_page(DummyPageHolder::create()) | |
51 { | |
52 } | |
53 | |
54 ScriptState* scriptState() { return ScriptState::forMainWorld(m_page->docume
nt().frame()); } | |
55 v8::Isolate* isolate() { return scriptState()->isolate(); } | |
56 | |
57 v8::MaybeLocal<v8::Value> eval(const char* s) | |
58 { | |
59 v8::Local<v8::String> source; | |
60 v8::Local<v8::Script> script; | |
61 if (!v8Call(v8::String::NewFromUtf8(isolate(), s, v8::NewStringType::kNo
rmal), source)) { | |
62 ADD_FAILURE(); | |
63 return v8::MaybeLocal<v8::Value>(); | |
64 } | |
65 if (!v8Call(v8::Script::Compile(scriptState()->context(), source), scrip
t)) { | |
66 ADD_FAILURE() << "Compilation fails"; | |
67 return v8::MaybeLocal<v8::Value>(); | |
68 } | |
69 return script->Run(scriptState()->context()); | |
70 } | |
71 v8::MaybeLocal<v8::Value> evalWithPrintingError(const char* s) | |
72 { | |
73 v8::TryCatch block(isolate()); | |
74 v8::MaybeLocal<v8::Value> r = eval(s); | |
75 if (block.HasCaught()) { | |
76 ADD_FAILURE() << toCoreString(block.Exception()->ToString(isolate())
).utf8().data(); | |
77 block.ReThrow(); | |
78 } | |
79 return r; | |
80 } | |
81 | |
82 private: | |
83 OwnPtr<DummyPageHolder> m_page; | |
84 }; | |
85 | |
86 TEST_F(ReadableStreamDataConsumerHandleTest, Create) | |
87 { | |
88 ScriptState::Scope scope(scriptState()); | |
89 ScriptValue stream(scriptState(), evalWithPrintingError("new ReadableStream"
)); | |
90 ASSERT_FALSE(stream.isEmpty()); | |
91 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
92 ASSERT_TRUE(handle); | |
93 MockClient* client = MockClient::create(); | |
94 Checkpoint checkpoint; | |
95 | |
96 InSequence s; | |
97 EXPECT_CALL(checkpoint, Call(1)); | |
98 EXPECT_CALL(*client, didGetReadable()); | |
99 EXPECT_CALL(checkpoint, Call(2)); | |
100 | |
101 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
102 ASSERT_TRUE(reader); | |
103 checkpoint.Call(1); | |
104 testing::runPendingTasks(); | |
105 checkpoint.Call(2); | |
106 } | |
107 | |
108 TEST_F(ReadableStreamDataConsumerHandleTest, EmptyStream) | |
109 { | |
110 ScriptState::Scope scope(scriptState()); | |
111 ScriptValue stream(scriptState(), evalWithPrintingError( | |
112 "new ReadableStream({start: c => c.close()})")); | |
113 ASSERT_FALSE(stream.isEmpty()); | |
114 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
115 ASSERT_TRUE(handle); | |
116 MockClient* client = MockClient::create(); | |
117 Checkpoint checkpoint; | |
118 | |
119 InSequence s; | |
120 EXPECT_CALL(checkpoint, Call(1)); | |
121 EXPECT_CALL(*client, didGetReadable()); | |
122 EXPECT_CALL(checkpoint, Call(2)); | |
123 EXPECT_CALL(*client, didGetReadable()); | |
124 EXPECT_CALL(checkpoint, Call(3)); | |
125 | |
126 char c; | |
127 size_t readBytes; | |
128 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
129 ASSERT_TRUE(reader); | |
130 checkpoint.Call(1); | |
131 testing::runPendingTasks(); | |
132 checkpoint.Call(2); | |
133 EXPECT_EQ(kShouldWait, reader->read(&c, 1, kNone, &readBytes)); | |
134 testing::runPendingTasks(); | |
135 checkpoint.Call(3); | |
136 EXPECT_EQ(kDone, reader->read(&c, 1, kNone, &readBytes)); | |
137 } | |
138 | |
139 TEST_F(ReadableStreamDataConsumerHandleTest, ErroredStream) | |
140 { | |
141 ScriptState::Scope scope(scriptState()); | |
142 ScriptValue stream(scriptState(), evalWithPrintingError( | |
143 "new ReadableStream({start: c => c.error()})")); | |
144 ASSERT_FALSE(stream.isEmpty()); | |
145 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
146 ASSERT_TRUE(handle); | |
147 MockClient* client = MockClient::create(); | |
148 Checkpoint checkpoint; | |
149 | |
150 InSequence s; | |
151 EXPECT_CALL(checkpoint, Call(1)); | |
152 EXPECT_CALL(*client, didGetReadable()); | |
153 EXPECT_CALL(checkpoint, Call(2)); | |
154 EXPECT_CALL(*client, didGetReadable()); | |
155 EXPECT_CALL(checkpoint, Call(3)); | |
156 | |
157 char c; | |
158 size_t readBytes; | |
159 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
160 ASSERT_TRUE(reader); | |
161 checkpoint.Call(1); | |
162 testing::runPendingTasks(); | |
163 checkpoint.Call(2); | |
164 EXPECT_EQ(kShouldWait, reader->read(&c, 1, kNone, &readBytes)); | |
165 testing::runPendingTasks(); | |
166 checkpoint.Call(3); | |
167 EXPECT_EQ(kUnexpectedError, reader->read(&c, 1, kNone, &readBytes)); | |
168 } | |
169 | |
170 TEST_F(ReadableStreamDataConsumerHandleTest, Read) | |
171 { | |
172 ScriptState::Scope scope(scriptState()); | |
173 ScriptValue stream(scriptState(), evalWithPrintingError( | |
174 "var controller;" | |
175 "var stream = new ReadableStream({start: c => controller = c});" | |
176 "controller.enqueue(new Uint8Array([0x43, 0x44, 0x45, 0x46]));" | |
177 "controller.enqueue(new Uint8Array([0x47, 0x48, 0x49, 0x4a]));" | |
178 "controller.close();" | |
179 "stream")); | |
180 ASSERT_FALSE(stream.isEmpty()); | |
181 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
182 ASSERT_TRUE(handle); | |
183 MockClient* client = MockClient::create(); | |
184 Checkpoint checkpoint; | |
185 | |
186 InSequence s; | |
187 EXPECT_CALL(checkpoint, Call(1)); | |
188 EXPECT_CALL(*client, didGetReadable()); | |
189 EXPECT_CALL(checkpoint, Call(2)); | |
190 EXPECT_CALL(*client, didGetReadable()); | |
191 EXPECT_CALL(checkpoint, Call(3)); | |
192 EXPECT_CALL(*client, didGetReadable()); | |
193 EXPECT_CALL(checkpoint, Call(4)); | |
194 EXPECT_CALL(*client, didGetReadable()); | |
195 EXPECT_CALL(checkpoint, Call(5)); | |
196 | |
197 char buffer[3]; | |
198 size_t readBytes; | |
199 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
200 ASSERT_TRUE(reader); | |
201 checkpoint.Call(1); | |
202 testing::runPendingTasks(); | |
203 checkpoint.Call(2); | |
204 EXPECT_EQ(kShouldWait, reader->read(buffer, 3, kNone, &readBytes)); | |
205 testing::runPendingTasks(); | |
206 checkpoint.Call(3); | |
207 EXPECT_EQ(kOk, reader->read(buffer, 3, kNone, &readBytes)); | |
208 EXPECT_EQ(3u, readBytes); | |
209 EXPECT_EQ(0x43, buffer[0]); | |
210 EXPECT_EQ(0x44, buffer[1]); | |
211 EXPECT_EQ(0x45, buffer[2]); | |
212 EXPECT_EQ(kOk, reader->read(buffer, 3, kNone, &readBytes)); | |
213 EXPECT_EQ(1u, readBytes); | |
214 EXPECT_EQ(0x46, buffer[0]); | |
215 EXPECT_EQ(kShouldWait, reader->read(buffer, 3, kNone, &readBytes)); | |
216 testing::runPendingTasks(); | |
217 checkpoint.Call(4); | |
218 EXPECT_EQ(kOk, reader->read(buffer, 3, kNone, &readBytes)); | |
219 EXPECT_EQ(3u, readBytes); | |
220 EXPECT_EQ(0x47, buffer[0]); | |
221 EXPECT_EQ(0x48, buffer[1]); | |
222 EXPECT_EQ(0x49, buffer[2]); | |
223 EXPECT_EQ(kOk, reader->read(buffer, 3, kNone, &readBytes)); | |
224 EXPECT_EQ(1u, readBytes); | |
225 EXPECT_EQ(0x4a, buffer[0]); | |
226 EXPECT_EQ(kShouldWait, reader->read(buffer, 3, kNone, &readBytes)); | |
227 testing::runPendingTasks(); | |
228 checkpoint.Call(5); | |
229 EXPECT_EQ(kDone, reader->read(buffer, 3, kNone, &readBytes)); | |
230 } | |
231 | |
232 TEST_F(ReadableStreamDataConsumerHandleTest, TwoPhaseRead) | |
233 { | |
234 ScriptState::Scope scope(scriptState()); | |
235 ScriptValue stream(scriptState(), evalWithPrintingError( | |
236 "var controller;" | |
237 "var stream = new ReadableStream({start: c => controller = c});" | |
238 "controller.enqueue(new Uint8Array([0x43, 0x44, 0x45, 0x46]));" | |
239 "controller.enqueue(new Uint8Array([0x47, 0x48, 0x49, 0x4a]));" | |
240 "controller.close();" | |
241 "stream")); | |
242 ASSERT_FALSE(stream.isEmpty()); | |
243 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
244 ASSERT_TRUE(handle); | |
245 MockClient* client = MockClient::create(); | |
246 Checkpoint checkpoint; | |
247 | |
248 InSequence s; | |
249 EXPECT_CALL(checkpoint, Call(1)); | |
250 EXPECT_CALL(*client, didGetReadable()); | |
251 EXPECT_CALL(checkpoint, Call(2)); | |
252 EXPECT_CALL(*client, didGetReadable()); | |
253 EXPECT_CALL(checkpoint, Call(3)); | |
254 EXPECT_CALL(*client, didGetReadable()); | |
255 EXPECT_CALL(checkpoint, Call(4)); | |
256 EXPECT_CALL(*client, didGetReadable()); | |
257 EXPECT_CALL(checkpoint, Call(5)); | |
258 | |
259 const void* buffer; | |
260 size_t available; | |
261 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
262 ASSERT_TRUE(reader); | |
263 checkpoint.Call(1); | |
264 testing::runPendingTasks(); | |
265 checkpoint.Call(2); | |
266 EXPECT_EQ(kShouldWait, reader->beginRead(&buffer, kNone, &available)); | |
267 testing::runPendingTasks(); | |
268 checkpoint.Call(3); | |
269 EXPECT_EQ(kOk, reader->beginRead(&buffer, kNone, &available)); | |
270 EXPECT_EQ(4u, available); | |
271 EXPECT_EQ(0x43, static_cast<const char*>(buffer)[0]); | |
272 EXPECT_EQ(0x44, static_cast<const char*>(buffer)[1]); | |
273 EXPECT_EQ(0x45, static_cast<const char*>(buffer)[2]); | |
274 EXPECT_EQ(0x46, static_cast<const char*>(buffer)[3]); | |
275 EXPECT_EQ(kOk, reader->endRead(0)); | |
276 EXPECT_EQ(kOk, reader->beginRead(&buffer, kNone, &available)); | |
277 EXPECT_EQ(4u, available); | |
278 EXPECT_EQ(0x43, static_cast<const char*>(buffer)[0]); | |
279 EXPECT_EQ(0x44, static_cast<const char*>(buffer)[1]); | |
280 EXPECT_EQ(0x45, static_cast<const char*>(buffer)[2]); | |
281 EXPECT_EQ(0x46, static_cast<const char*>(buffer)[3]); | |
282 EXPECT_EQ(kOk, reader->endRead(1)); | |
283 EXPECT_EQ(kOk, reader->beginRead(&buffer, kNone, &available)); | |
284 EXPECT_EQ(3u, available); | |
285 EXPECT_EQ(0x44, static_cast<const char*>(buffer)[0]); | |
286 EXPECT_EQ(0x45, static_cast<const char*>(buffer)[1]); | |
287 EXPECT_EQ(0x46, static_cast<const char*>(buffer)[2]); | |
288 EXPECT_EQ(kOk, reader->endRead(3)); | |
289 EXPECT_EQ(kShouldWait, reader->beginRead(&buffer, kNone, &available)); | |
290 testing::runPendingTasks(); | |
291 checkpoint.Call(4); | |
292 EXPECT_EQ(kOk, reader->beginRead(&buffer, kNone, &available)); | |
293 EXPECT_EQ(4u, available); | |
294 EXPECT_EQ(0x47, static_cast<const char*>(buffer)[0]); | |
295 EXPECT_EQ(0x48, static_cast<const char*>(buffer)[1]); | |
296 EXPECT_EQ(0x49, static_cast<const char*>(buffer)[2]); | |
297 EXPECT_EQ(0x4a, static_cast<const char*>(buffer)[3]); | |
298 EXPECT_EQ(kOk, reader->endRead(4)); | |
299 EXPECT_EQ(kShouldWait, reader->beginRead(&buffer, kNone, &available)); | |
300 testing::runPendingTasks(); | |
301 checkpoint.Call(5); | |
302 EXPECT_EQ(kDone, reader->beginRead(&buffer, kNone, &available)); | |
303 } | |
304 | |
305 TEST_F(ReadableStreamDataConsumerHandleTest, LockedStream) | |
306 { | |
307 ScriptState::Scope scope(scriptState()); | |
308 ScriptValue stream(scriptState(), evalWithPrintingError( | |
309 "var stream = new ReadableStream;" | |
310 "stream.getReader();" | |
311 "stream")); | |
312 ASSERT_FALSE(stream.isEmpty()); | |
313 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
314 ASSERT_TRUE(handle); | |
315 MockClient* client = MockClient::create(); | |
316 Checkpoint checkpoint; | |
317 | |
318 InSequence s; | |
319 EXPECT_CALL(checkpoint, Call(1)); | |
320 EXPECT_CALL(*client, didGetReadable()); | |
321 EXPECT_CALL(checkpoint, Call(2)); | |
322 | |
323 char c; | |
324 size_t readBytes; | |
325 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
326 ASSERT_TRUE(reader); | |
327 checkpoint.Call(1); | |
328 testing::runPendingTasks(); | |
329 checkpoint.Call(2); | |
330 EXPECT_EQ(kUnexpectedError, reader->read(&c, 1, kNone, &readBytes)); | |
331 } | |
332 | |
333 TEST_F(ReadableStreamDataConsumerHandleTest, EnqueueUndefined) | |
334 { | |
335 ScriptState::Scope scope(scriptState()); | |
336 ScriptValue stream(scriptState(), evalWithPrintingError( | |
337 "var controller;" | |
338 "var stream = new ReadableStream({start: c => controller = c});" | |
339 "controller.enqueue(undefined);" | |
340 "controller.close();" | |
341 "stream")); | |
342 ASSERT_FALSE(stream.isEmpty()); | |
343 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
344 ASSERT_TRUE(handle); | |
345 MockClient* client = MockClient::create(); | |
346 Checkpoint checkpoint; | |
347 | |
348 InSequence s; | |
349 EXPECT_CALL(checkpoint, Call(1)); | |
350 EXPECT_CALL(*client, didGetReadable()); | |
351 EXPECT_CALL(checkpoint, Call(2)); | |
352 EXPECT_CALL(*client, didGetReadable()); | |
353 EXPECT_CALL(checkpoint, Call(3)); | |
354 | |
355 const void* buffer; | |
356 size_t available; | |
357 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
358 ASSERT_TRUE(reader); | |
359 checkpoint.Call(1); | |
360 testing::runPendingTasks(); | |
361 checkpoint.Call(2); | |
362 EXPECT_EQ(kShouldWait, reader->beginRead(&buffer, kNone, &available)); | |
363 testing::runPendingTasks(); | |
364 checkpoint.Call(3); | |
365 EXPECT_EQ(kUnexpectedError, reader->beginRead(&buffer, kNone, &available)); | |
366 } | |
367 | |
368 TEST_F(ReadableStreamDataConsumerHandleTest, EnqueueNull) | |
369 { | |
370 ScriptState::Scope scope(scriptState()); | |
371 ScriptValue stream(scriptState(), evalWithPrintingError( | |
372 "var controller;" | |
373 "var stream = new ReadableStream({start: c => controller = c});" | |
374 "controller.enqueue(null);" | |
375 "controller.close();" | |
376 "stream")); | |
377 ASSERT_FALSE(stream.isEmpty()); | |
378 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
379 ASSERT_TRUE(handle); | |
380 MockClient* client = MockClient::create(); | |
381 Checkpoint checkpoint; | |
382 | |
383 InSequence s; | |
384 EXPECT_CALL(checkpoint, Call(1)); | |
385 EXPECT_CALL(*client, didGetReadable()); | |
386 EXPECT_CALL(checkpoint, Call(2)); | |
387 EXPECT_CALL(*client, didGetReadable()); | |
388 EXPECT_CALL(checkpoint, Call(3)); | |
389 | |
390 const void* buffer; | |
391 size_t available; | |
392 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
393 ASSERT_TRUE(reader); | |
394 checkpoint.Call(1); | |
395 testing::runPendingTasks(); | |
396 checkpoint.Call(2); | |
397 EXPECT_EQ(kShouldWait, reader->beginRead(&buffer, kNone, &available)); | |
398 testing::runPendingTasks(); | |
399 checkpoint.Call(3); | |
400 EXPECT_EQ(kUnexpectedError, reader->beginRead(&buffer, kNone, &available)); | |
401 } | |
402 | |
403 TEST_F(ReadableStreamDataConsumerHandleTest, EnqueueString) | |
404 { | |
405 ScriptState::Scope scope(scriptState()); | |
406 ScriptValue stream(scriptState(), evalWithPrintingError( | |
407 "var controller;" | |
408 "var stream = new ReadableStream({start: c => controller = c});" | |
409 "controller.enqueue('hello');" | |
410 "controller.close();" | |
411 "stream")); | |
412 ASSERT_FALSE(stream.isEmpty()); | |
413 OwnPtr<ReadableStreamDataConsumerHandle> handle = ReadableStreamDataConsumer
Handle::create(scriptState(), stream.v8Value()); | |
414 ASSERT_TRUE(handle); | |
415 MockClient* client = MockClient::create(); | |
416 Checkpoint checkpoint; | |
417 | |
418 InSequence s; | |
419 EXPECT_CALL(checkpoint, Call(1)); | |
420 EXPECT_CALL(*client, didGetReadable()); | |
421 EXPECT_CALL(checkpoint, Call(2)); | |
422 EXPECT_CALL(*client, didGetReadable()); | |
423 EXPECT_CALL(checkpoint, Call(3)); | |
424 | |
425 const void* buffer; | |
426 size_t available; | |
427 OwnPtr<FetchDataConsumerHandle::Reader> reader = handle->obtainReader(client
); | |
428 ASSERT_TRUE(reader); | |
429 checkpoint.Call(1); | |
430 testing::runPendingTasks(); | |
431 checkpoint.Call(2); | |
432 EXPECT_EQ(kShouldWait, reader->beginRead(&buffer, kNone, &available)); | |
433 testing::runPendingTasks(); | |
434 checkpoint.Call(3); | |
435 EXPECT_EQ(kUnexpectedError, reader->beginRead(&buffer, kNone, &available)); | |
436 } | |
437 | |
438 } // namespace | |
439 | |
440 } // namespace blink | |
441 | |
OLD | NEW |