| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 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 "modules/fetch/ReadableStreamBytesConsumer.h" |
| 6 |
| 7 #include "bindings/core/v8/ScriptState.h" |
| 8 #include "bindings/core/v8/V8BindingMacros.h" |
| 9 #include "bindings/core/v8/V8GCController.h" |
| 10 #include "core/dom/Document.h" |
| 11 #include "core/streams/ReadableStreamOperations.h" |
| 12 #include "core/testing/DummyPageHolder.h" |
| 13 #include "modules/fetch/BytesConsumerTestUtil.h" |
| 14 #include "platform/heap/Handle.h" |
| 15 #include "platform/testing/UnitTestHelpers.h" |
| 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 #include <memory> |
| 19 #include <v8.h> |
| 20 |
| 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 = BytesConsumer::Result; |
| 29 using PublicState = BytesConsumer::PublicState; |
| 30 |
| 31 class MockClient : public GarbageCollectedFinalized<MockClient>, |
| 32 public BytesConsumer::Client { |
| 33 USING_GARBAGE_COLLECTED_MIXIN(MockClient); |
| 34 |
| 35 public: |
| 36 static MockClient* create() { return new StrictMock<MockClient>(); } |
| 37 MOCK_METHOD0(onStateChange, void()); |
| 38 |
| 39 DEFINE_INLINE_TRACE() {} |
| 40 |
| 41 protected: |
| 42 MockClient() = default; |
| 43 }; |
| 44 |
| 45 class ReadableStreamBytesConsumerTest : public ::testing::Test { |
| 46 public: |
| 47 ReadableStreamBytesConsumerTest() : m_page(DummyPageHolder::create()) {} |
| 48 |
| 49 ScriptState* getScriptState() { |
| 50 return ScriptState::forMainWorld(m_page->document().frame()); |
| 51 } |
| 52 v8::Isolate* isolate() { return getScriptState()->isolate(); } |
| 53 |
| 54 v8::MaybeLocal<v8::Value> eval(const char* s) { |
| 55 v8::Local<v8::String> source; |
| 56 v8::Local<v8::Script> script; |
| 57 v8::MicrotasksScope microtasks(isolate(), |
| 58 v8::MicrotasksScope::kDoNotRunMicrotasks); |
| 59 if (!v8Call( |
| 60 v8::String::NewFromUtf8(isolate(), s, v8::NewStringType::kNormal), |
| 61 source)) { |
| 62 ADD_FAILURE(); |
| 63 return v8::MaybeLocal<v8::Value>(); |
| 64 } |
| 65 if (!v8Call(v8::Script::Compile(getScriptState()->context(), source), |
| 66 script)) { |
| 67 ADD_FAILURE() << "Compilation fails"; |
| 68 return v8::MaybeLocal<v8::Value>(); |
| 69 } |
| 70 return script->Run(getScriptState()->context()); |
| 71 } |
| 72 v8::MaybeLocal<v8::Value> evalWithPrintingError(const char* s) { |
| 73 v8::TryCatch block(isolate()); |
| 74 v8::MaybeLocal<v8::Value> r = eval(s); |
| 75 if (block.HasCaught()) { |
| 76 ADD_FAILURE() |
| 77 << toCoreString(block.Exception()->ToString(isolate())).utf8().data(); |
| 78 block.ReThrow(); |
| 79 } |
| 80 return r; |
| 81 } |
| 82 |
| 83 ReadableStreamBytesConsumer* createConsumer(ScriptValue stream) { |
| 84 NonThrowableExceptionState es; |
| 85 ScriptValue reader = |
| 86 ReadableStreamOperations::getReader(getScriptState(), stream, es); |
| 87 DCHECK(!reader.isEmpty()); |
| 88 DCHECK(reader.v8Value()->IsObject()); |
| 89 return new ReadableStreamBytesConsumer(getScriptState(), reader); |
| 90 } |
| 91 |
| 92 void gc() { V8GCController::collectAllGarbageForTesting(isolate()); } |
| 93 |
| 94 private: |
| 95 std::unique_ptr<DummyPageHolder> m_page; |
| 96 }; |
| 97 |
| 98 TEST_F(ReadableStreamBytesConsumerTest, Create) { |
| 99 ScriptState::Scope scope(getScriptState()); |
| 100 ScriptValue stream(getScriptState(), |
| 101 evalWithPrintingError("new ReadableStream")); |
| 102 ASSERT_FALSE(stream.isEmpty()); |
| 103 Persistent<BytesConsumer> consumer = createConsumer(stream); |
| 104 |
| 105 EXPECT_EQ(PublicState::ReadableOrWaiting, consumer->getPublicState()); |
| 106 } |
| 107 |
| 108 TEST_F(ReadableStreamBytesConsumerTest, EmptyStream) { |
| 109 ScriptState::Scope scope(getScriptState()); |
| 110 ScriptValue stream( |
| 111 getScriptState(), |
| 112 evalWithPrintingError("new ReadableStream({start: c => c.close()})")); |
| 113 ASSERT_FALSE(stream.isEmpty()); |
| 114 Persistent<BytesConsumer> consumer = createConsumer(stream); |
| 115 Persistent<MockClient> client = MockClient::create(); |
| 116 consumer->setClient(client); |
| 117 |
| 118 Checkpoint checkpoint; |
| 119 InSequence s; |
| 120 EXPECT_CALL(checkpoint, Call(1)); |
| 121 EXPECT_CALL(checkpoint, Call(2)); |
| 122 EXPECT_CALL(checkpoint, Call(3)); |
| 123 EXPECT_CALL(*client, onStateChange()); |
| 124 EXPECT_CALL(checkpoint, Call(4)); |
| 125 |
| 126 const char* buffer = nullptr; |
| 127 size_t available = 0; |
| 128 checkpoint.Call(1); |
| 129 testing::runPendingTasks(); |
| 130 checkpoint.Call(2); |
| 131 EXPECT_EQ(PublicState::ReadableOrWaiting, consumer->getPublicState()); |
| 132 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 133 checkpoint.Call(3); |
| 134 testing::runPendingTasks(); |
| 135 checkpoint.Call(4); |
| 136 EXPECT_EQ(PublicState::Closed, consumer->getPublicState()); |
| 137 EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available)); |
| 138 } |
| 139 |
| 140 TEST_F(ReadableStreamBytesConsumerTest, ErroredStream) { |
| 141 ScriptState::Scope scope(getScriptState()); |
| 142 ScriptValue stream( |
| 143 getScriptState(), |
| 144 evalWithPrintingError("new ReadableStream({start: c => c.error()})")); |
| 145 ASSERT_FALSE(stream.isEmpty()); |
| 146 Persistent<BytesConsumer> consumer = createConsumer(stream); |
| 147 Persistent<MockClient> client = MockClient::create(); |
| 148 consumer->setClient(client); |
| 149 Checkpoint checkpoint; |
| 150 |
| 151 InSequence s; |
| 152 EXPECT_CALL(checkpoint, Call(1)); |
| 153 EXPECT_CALL(checkpoint, Call(2)); |
| 154 EXPECT_CALL(checkpoint, Call(3)); |
| 155 EXPECT_CALL(*client, onStateChange()); |
| 156 EXPECT_CALL(checkpoint, Call(4)); |
| 157 |
| 158 const char* buffer = nullptr; |
| 159 size_t available = 0; |
| 160 checkpoint.Call(1); |
| 161 testing::runPendingTasks(); |
| 162 checkpoint.Call(2); |
| 163 EXPECT_EQ(PublicState::ReadableOrWaiting, consumer->getPublicState()); |
| 164 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 165 checkpoint.Call(3); |
| 166 testing::runPendingTasks(); |
| 167 checkpoint.Call(4); |
| 168 EXPECT_EQ(PublicState::Errored, consumer->getPublicState()); |
| 169 EXPECT_EQ(Result::Error, consumer->beginRead(&buffer, &available)); |
| 170 } |
| 171 |
| 172 TEST_F(ReadableStreamBytesConsumerTest, TwoPhaseRead) { |
| 173 ScriptState::Scope scope(getScriptState()); |
| 174 ScriptValue stream( |
| 175 getScriptState(), |
| 176 evalWithPrintingError( |
| 177 "var controller;" |
| 178 "var stream = new ReadableStream({start: c => controller = c});" |
| 179 "controller.enqueue(new Uint8Array());" |
| 180 "controller.enqueue(new Uint8Array([0x43, 0x44, 0x45, 0x46]));" |
| 181 "controller.enqueue(new Uint8Array([0x47, 0x48, 0x49, 0x4a]));" |
| 182 "controller.close();" |
| 183 "stream")); |
| 184 ASSERT_FALSE(stream.isEmpty()); |
| 185 Persistent<BytesConsumer> consumer = createConsumer(stream); |
| 186 Persistent<MockClient> client = MockClient::create(); |
| 187 consumer->setClient(client); |
| 188 Checkpoint checkpoint; |
| 189 |
| 190 InSequence s; |
| 191 EXPECT_CALL(checkpoint, Call(1)); |
| 192 EXPECT_CALL(checkpoint, Call(2)); |
| 193 EXPECT_CALL(checkpoint, Call(3)); |
| 194 EXPECT_CALL(*client, onStateChange()); |
| 195 EXPECT_CALL(checkpoint, Call(4)); |
| 196 EXPECT_CALL(checkpoint, Call(5)); |
| 197 EXPECT_CALL(*client, onStateChange()); |
| 198 EXPECT_CALL(checkpoint, Call(6)); |
| 199 EXPECT_CALL(checkpoint, Call(7)); |
| 200 EXPECT_CALL(*client, onStateChange()); |
| 201 EXPECT_CALL(checkpoint, Call(8)); |
| 202 EXPECT_CALL(checkpoint, Call(9)); |
| 203 EXPECT_CALL(*client, onStateChange()); |
| 204 EXPECT_CALL(checkpoint, Call(10)); |
| 205 |
| 206 const char* buffer = nullptr; |
| 207 size_t available = 0; |
| 208 checkpoint.Call(1); |
| 209 testing::runPendingTasks(); |
| 210 checkpoint.Call(2); |
| 211 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 212 checkpoint.Call(3); |
| 213 testing::runPendingTasks(); |
| 214 checkpoint.Call(4); |
| 215 EXPECT_EQ(Result::Ok, consumer->beginRead(&buffer, &available)); |
| 216 ASSERT_EQ(0u, available); |
| 217 EXPECT_EQ(Result::Ok, consumer->endRead(0)); |
| 218 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 219 checkpoint.Call(5); |
| 220 testing::runPendingTasks(); |
| 221 checkpoint.Call(6); |
| 222 EXPECT_EQ(PublicState::ReadableOrWaiting, consumer->getPublicState()); |
| 223 EXPECT_EQ(Result::Ok, consumer->beginRead(&buffer, &available)); |
| 224 ASSERT_EQ(4u, available); |
| 225 EXPECT_EQ(0x43, buffer[0]); |
| 226 EXPECT_EQ(0x44, buffer[1]); |
| 227 EXPECT_EQ(0x45, buffer[2]); |
| 228 EXPECT_EQ(0x46, buffer[3]); |
| 229 EXPECT_EQ(Result::Ok, consumer->endRead(0)); |
| 230 EXPECT_EQ(Result::Ok, consumer->beginRead(&buffer, &available)); |
| 231 ASSERT_EQ(4u, available); |
| 232 EXPECT_EQ(0x43, buffer[0]); |
| 233 EXPECT_EQ(0x44, buffer[1]); |
| 234 EXPECT_EQ(0x45, buffer[2]); |
| 235 EXPECT_EQ(0x46, buffer[3]); |
| 236 EXPECT_EQ(Result::Ok, consumer->endRead(1)); |
| 237 EXPECT_EQ(Result::Ok, consumer->beginRead(&buffer, &available)); |
| 238 ASSERT_EQ(3u, available); |
| 239 EXPECT_EQ(0x44, buffer[0]); |
| 240 EXPECT_EQ(0x45, buffer[1]); |
| 241 EXPECT_EQ(0x46, buffer[2]); |
| 242 EXPECT_EQ(Result::Ok, consumer->endRead(3)); |
| 243 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 244 checkpoint.Call(7); |
| 245 testing::runPendingTasks(); |
| 246 checkpoint.Call(8); |
| 247 EXPECT_EQ(PublicState::ReadableOrWaiting, consumer->getPublicState()); |
| 248 EXPECT_EQ(Result::Ok, consumer->beginRead(&buffer, &available)); |
| 249 ASSERT_EQ(4u, available); |
| 250 EXPECT_EQ(0x47, buffer[0]); |
| 251 EXPECT_EQ(0x48, buffer[1]); |
| 252 EXPECT_EQ(0x49, buffer[2]); |
| 253 EXPECT_EQ(0x4a, buffer[3]); |
| 254 EXPECT_EQ(Result::Ok, consumer->endRead(4)); |
| 255 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 256 checkpoint.Call(9); |
| 257 testing::runPendingTasks(); |
| 258 checkpoint.Call(10); |
| 259 EXPECT_EQ(PublicState::Closed, consumer->getPublicState()); |
| 260 EXPECT_EQ(Result::Done, consumer->beginRead(&buffer, &available)); |
| 261 } |
| 262 |
| 263 TEST_F(ReadableStreamBytesConsumerTest, EnqueueUndefined) { |
| 264 ScriptState::Scope scope(getScriptState()); |
| 265 ScriptValue stream( |
| 266 getScriptState(), |
| 267 evalWithPrintingError( |
| 268 "var controller;" |
| 269 "var stream = new ReadableStream({start: c => controller = c});" |
| 270 "controller.enqueue(undefined);" |
| 271 "controller.close();" |
| 272 "stream")); |
| 273 ASSERT_FALSE(stream.isEmpty()); |
| 274 Persistent<BytesConsumer> consumer = createConsumer(stream); |
| 275 Persistent<MockClient> client = MockClient::create(); |
| 276 consumer->setClient(client); |
| 277 Checkpoint checkpoint; |
| 278 |
| 279 InSequence s; |
| 280 EXPECT_CALL(checkpoint, Call(1)); |
| 281 EXPECT_CALL(checkpoint, Call(2)); |
| 282 EXPECT_CALL(checkpoint, Call(3)); |
| 283 EXPECT_CALL(*client, onStateChange()); |
| 284 EXPECT_CALL(checkpoint, Call(4)); |
| 285 |
| 286 const char* buffer = nullptr; |
| 287 size_t available = 0; |
| 288 checkpoint.Call(1); |
| 289 testing::runPendingTasks(); |
| 290 checkpoint.Call(2); |
| 291 EXPECT_EQ(PublicState::ReadableOrWaiting, consumer->getPublicState()); |
| 292 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 293 checkpoint.Call(3); |
| 294 testing::runPendingTasks(); |
| 295 checkpoint.Call(4); |
| 296 EXPECT_EQ(PublicState::Errored, consumer->getPublicState()); |
| 297 EXPECT_EQ(Result::Error, consumer->beginRead(&buffer, &available)); |
| 298 } |
| 299 |
| 300 TEST_F(ReadableStreamBytesConsumerTest, EnqueueNull) { |
| 301 ScriptState::Scope scope(getScriptState()); |
| 302 ScriptValue stream( |
| 303 getScriptState(), |
| 304 evalWithPrintingError( |
| 305 "var controller;" |
| 306 "var stream = new ReadableStream({start: c => controller = c});" |
| 307 "controller.enqueue(null);" |
| 308 "controller.close();" |
| 309 "stream")); |
| 310 |
| 311 ASSERT_FALSE(stream.isEmpty()); |
| 312 Persistent<BytesConsumer> consumer = createConsumer(stream); |
| 313 Persistent<MockClient> client = MockClient::create(); |
| 314 consumer->setClient(client); |
| 315 Checkpoint checkpoint; |
| 316 |
| 317 InSequence s; |
| 318 EXPECT_CALL(checkpoint, Call(1)); |
| 319 EXPECT_CALL(checkpoint, Call(2)); |
| 320 EXPECT_CALL(checkpoint, Call(3)); |
| 321 EXPECT_CALL(*client, onStateChange()); |
| 322 EXPECT_CALL(checkpoint, Call(4)); |
| 323 |
| 324 const char* buffer = nullptr; |
| 325 size_t available = 0; |
| 326 checkpoint.Call(1); |
| 327 testing::runPendingTasks(); |
| 328 checkpoint.Call(2); |
| 329 EXPECT_EQ(PublicState::ReadableOrWaiting, consumer->getPublicState()); |
| 330 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 331 checkpoint.Call(3); |
| 332 testing::runPendingTasks(); |
| 333 checkpoint.Call(4); |
| 334 EXPECT_EQ(PublicState::Errored, consumer->getPublicState()); |
| 335 EXPECT_EQ(Result::Error, consumer->beginRead(&buffer, &available)); |
| 336 } |
| 337 |
| 338 TEST_F(ReadableStreamBytesConsumerTest, EnqueueString) { |
| 339 ScriptState::Scope scope(getScriptState()); |
| 340 ScriptValue stream( |
| 341 getScriptState(), |
| 342 evalWithPrintingError( |
| 343 "var controller;" |
| 344 "var stream = new ReadableStream({start: c => controller = c});" |
| 345 "controller.enqueue('hello');" |
| 346 "controller.close();" |
| 347 "stream")); |
| 348 ASSERT_FALSE(stream.isEmpty()); |
| 349 Persistent<BytesConsumer> consumer = createConsumer(stream); |
| 350 Persistent<MockClient> client = MockClient::create(); |
| 351 consumer->setClient(client); |
| 352 Checkpoint checkpoint; |
| 353 |
| 354 InSequence s; |
| 355 EXPECT_CALL(checkpoint, Call(1)); |
| 356 EXPECT_CALL(checkpoint, Call(2)); |
| 357 EXPECT_CALL(checkpoint, Call(3)); |
| 358 EXPECT_CALL(*client, onStateChange()); |
| 359 EXPECT_CALL(checkpoint, Call(4)); |
| 360 |
| 361 const char* buffer = nullptr; |
| 362 size_t available = 0; |
| 363 checkpoint.Call(1); |
| 364 testing::runPendingTasks(); |
| 365 checkpoint.Call(2); |
| 366 EXPECT_EQ(PublicState::ReadableOrWaiting, consumer->getPublicState()); |
| 367 EXPECT_EQ(Result::ShouldWait, consumer->beginRead(&buffer, &available)); |
| 368 checkpoint.Call(3); |
| 369 testing::runPendingTasks(); |
| 370 checkpoint.Call(4); |
| 371 EXPECT_EQ(PublicState::Errored, consumer->getPublicState()); |
| 372 EXPECT_EQ(Result::Error, consumer->beginRead(&buffer, &available)); |
| 373 } |
| 374 |
| 375 } // namespace |
| 376 |
| 377 } // namespace blink |
| OLD | NEW |