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