| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "core/fetch/BlobBytesConsumer.h" |
| |
| #include "core/fetch/BytesConsumerTestUtil.h" |
| #include "core/fetch/DataConsumerHandleTestUtil.h" |
| #include "core/loader/ThreadableLoader.h" |
| #include "core/testing/PageTestBase.h" |
| #include "platform/blob/BlobData.h" |
| #include "platform/loader/fetch/ResourceError.h" |
| #include "platform/loader/fetch/ResourceResponse.h" |
| #include "platform/network/EncodedFormData.h" |
| #include "platform/testing/UnitTestHelpers.h" |
| #include "platform/wtf/text/WTFString.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| using DataConsumerCommand = DataConsumerHandleTestUtil::Command; |
| using PublicState = BytesConsumer::PublicState; |
| using ReplayingHandle = DataConsumerHandleTestUtil::ReplayingHandle; |
| using Result = BytesConsumer::Result; |
| |
| class TestThreadableLoader : public ThreadableLoader { |
| public: |
| ~TestThreadableLoader() override { |
| EXPECT_FALSE(should_be_cancelled_ && !is_cancelled_) |
| << "The loader should be cancelled but is not cancelled."; |
| } |
| |
| void Start(const ResourceRequest& request) override { is_started_ = true; } |
| |
| void OverrideTimeout(unsigned long timeout_milliseconds) override { |
| ADD_FAILURE() << "overrideTimeout should not be called."; |
| } |
| |
| void Cancel() override { is_cancelled_ = true; } |
| void Detach() override { NOTREACHED(); } |
| |
| bool IsStarted() const { return is_started_; } |
| bool IsCancelled() const { return is_cancelled_; } |
| void SetShouldBeCancelled() { should_be_cancelled_ = true; } |
| |
| private: |
| bool is_started_ = false; |
| bool is_cancelled_ = false; |
| bool should_be_cancelled_ = false; |
| }; |
| |
| class SyncLoadingTestThreadableLoader : public ThreadableLoader { |
| public: |
| ~SyncLoadingTestThreadableLoader() override { DCHECK(!handle_); } |
| |
| void Start(const ResourceRequest& request) override { |
| is_started_ = true; |
| client_->DidReceiveResponse(0, ResourceResponse(), std::move(handle_)); |
| client_->DidFinishLoading(0, 0); |
| } |
| |
| void OverrideTimeout(unsigned long timeout_milliseconds) override { |
| ADD_FAILURE() << "overrideTimeout should not be called."; |
| } |
| |
| void Cancel() override { is_cancelled_ = true; } |
| void Detach() override { NOTREACHED(); } |
| |
| bool IsStarted() const { return is_started_; } |
| bool IsCancelled() const { return is_cancelled_; } |
| |
| void SetClient(ThreadableLoaderClient* client) { client_ = client; } |
| |
| void SetHandle(std::unique_ptr<WebDataConsumerHandle> handle) { |
| handle_ = std::move(handle); |
| } |
| |
| private: |
| bool is_started_ = false; |
| bool is_cancelled_ = false; |
| ThreadableLoaderClient* client_ = nullptr; |
| std::unique_ptr<WebDataConsumerHandle> handle_; |
| }; |
| |
| class SyncErrorTestThreadableLoader : public ThreadableLoader { |
| public: |
| ~SyncErrorTestThreadableLoader() override {} |
| |
| void Start(const ResourceRequest& request) override { |
| is_started_ = true; |
| client_->DidFail(ResourceError::Failure(NullURL())); |
| } |
| |
| void OverrideTimeout(unsigned long timeout_milliseconds) override { |
| ADD_FAILURE() << "overrideTimeout should not be called."; |
| } |
| |
| void Cancel() override { is_cancelled_ = true; } |
| void Detach() override { NOTREACHED(); } |
| |
| bool IsStarted() const { return is_started_; } |
| bool IsCancelled() const { return is_cancelled_; } |
| |
| void SetClient(ThreadableLoaderClient* client) { client_ = client; } |
| |
| private: |
| bool is_started_ = false; |
| bool is_cancelled_ = false; |
| ThreadableLoaderClient* client_ = nullptr; |
| }; |
| |
| class BlobBytesConsumerTestClient final |
| : public GarbageCollectedFinalized<BlobBytesConsumerTestClient>, |
| public BytesConsumer::Client { |
| USING_GARBAGE_COLLECTED_MIXIN(BlobBytesConsumerTestClient); |
| |
| public: |
| void OnStateChange() override { ++num_on_state_change_called_; } |
| String DebugName() const override { return "BlobBytesConsumerTestClient"; } |
| int NumOnStateChangeCalled() const { return num_on_state_change_called_; } |
| |
| private: |
| int num_on_state_change_called_ = 0; |
| }; |
| |
| class BlobBytesConsumerTest : public PageTestBase { |
| public: |
| void SetUp() override { PageTestBase::SetUp(IntSize(1, 1)); } |
| }; |
| |
| TEST_F(BlobBytesConsumerTest, TwoPhaseRead) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| std::unique_ptr<ReplayingHandle> src = ReplayingHandle::Create(); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kData, "hello, ")); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kWait)); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kData, "world")); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kDone)); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| |
| const char* buffer = nullptr; |
| size_t available = 0; |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_TRUE(loader->IsStarted()); |
| EXPECT_FALSE(consumer->DrainAsBlobDataHandle( |
| BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize)); |
| EXPECT_FALSE(consumer->DrainAsFormData()); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| |
| consumer->DidReceiveResponse(0, ResourceResponse(), std::move(src)); |
| consumer->DidFinishLoading(0, 0); |
| |
| auto result = (new BytesConsumerTestUtil::TwoPhaseReader(consumer))->Run(); |
| EXPECT_EQ(Result::kDone, result.first); |
| EXPECT_EQ("hello, world", |
| BytesConsumerTestUtil::CharVectorToString(result.second)); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, FailLoading) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| |
| const char* buffer = nullptr; |
| size_t available = 0; |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_TRUE(loader->IsStarted()); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| |
| int num_on_state_change_called = client->NumOnStateChangeCalled(); |
| consumer->DidFail(ResourceError::Failure(NullURL())); |
| |
| EXPECT_EQ(num_on_state_change_called + 1, client->NumOnStateChangeCalled()); |
| EXPECT_EQ(PublicState::kErrored, consumer->GetPublicState()); |
| EXPECT_EQ(Result::kError, consumer->BeginRead(&buffer, &available)); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, FailLoadingAfterResponseReceived) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_TRUE(loader->IsStarted()); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| |
| int num_on_state_change_called = client->NumOnStateChangeCalled(); |
| consumer->DidReceiveResponse( |
| 0, ResourceResponse(), |
| DataConsumerHandleTestUtil::CreateWaitingDataConsumerHandle()); |
| EXPECT_EQ(num_on_state_change_called + 1, client->NumOnStateChangeCalled()); |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| |
| consumer->DidFail(ResourceError::Failure(NullURL())); |
| EXPECT_EQ(num_on_state_change_called + 2, client->NumOnStateChangeCalled()); |
| EXPECT_EQ(PublicState::kErrored, consumer->GetPublicState()); |
| EXPECT_EQ(Result::kError, consumer->BeginRead(&buffer, &available)); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, FailAccessControlCheck) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_TRUE(loader->IsStarted()); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| |
| int num_on_state_change_called = client->NumOnStateChangeCalled(); |
| consumer->DidFail(ResourceError::Failure(NullURL())); |
| EXPECT_EQ(num_on_state_change_called + 1, client->NumOnStateChangeCalled()); |
| |
| EXPECT_EQ(PublicState::kErrored, consumer->GetPublicState()); |
| EXPECT_EQ(Result::kError, consumer->BeginRead(&buffer, &available)); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, CancelBeforeStarting) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| |
| consumer->Cancel(); |
| // This should be FALSE in production, but TRUE here because we set the |
| // loader before starting loading in tests. |
| EXPECT_TRUE(loader->IsCancelled()); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(Result::kDone, consumer->BeginRead(&buffer, &available)); |
| EXPECT_EQ(PublicState::kClosed, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| EXPECT_EQ(0, client->NumOnStateChangeCalled()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, CancelAfterStarting) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_TRUE(loader->IsStarted()); |
| EXPECT_EQ(0, client->NumOnStateChangeCalled()); |
| |
| consumer->Cancel(); |
| EXPECT_TRUE(loader->IsCancelled()); |
| EXPECT_EQ(PublicState::kClosed, consumer->GetPublicState()); |
| EXPECT_EQ(Result::kDone, consumer->BeginRead(&buffer, &available)); |
| EXPECT_EQ(0, client->NumOnStateChangeCalled()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, ReadLastChunkBeforeDidFinishLoadingArrives) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| std::unique_ptr<ReplayingHandle> src = ReplayingHandle::Create(); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kData, "hello")); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kDone)); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_TRUE(loader->IsStarted()); |
| EXPECT_EQ(0, client->NumOnStateChangeCalled()); |
| |
| consumer->DidReceiveResponse(0, ResourceResponse(), std::move(src)); |
| EXPECT_EQ(1, client->NumOnStateChangeCalled()); |
| testing::RunPendingTasks(); |
| EXPECT_EQ(2, client->NumOnStateChangeCalled()); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| ASSERT_EQ(Result::kOk, consumer->BeginRead(&buffer, &available)); |
| ASSERT_EQ(5u, available); |
| EXPECT_EQ("hello", String(buffer, available)); |
| ASSERT_EQ(Result::kOk, consumer->EndRead(available)); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| ASSERT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| |
| consumer->DidFinishLoading(0, 0); |
| EXPECT_EQ(3, client->NumOnStateChangeCalled()); |
| EXPECT_EQ(PublicState::kClosed, consumer->GetPublicState()); |
| ASSERT_EQ(Result::kDone, consumer->BeginRead(&buffer, &available)); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, ReadLastChunkAfterDidFinishLoadingArrives) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| std::unique_ptr<ReplayingHandle> src = ReplayingHandle::Create(); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kData, "hello")); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kDone)); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_TRUE(loader->IsStarted()); |
| EXPECT_EQ(0, client->NumOnStateChangeCalled()); |
| |
| consumer->DidReceiveResponse(0, ResourceResponse(), std::move(src)); |
| EXPECT_EQ(1, client->NumOnStateChangeCalled()); |
| testing::RunPendingTasks(); |
| EXPECT_EQ(2, client->NumOnStateChangeCalled()); |
| |
| consumer->DidFinishLoading(0, 0); |
| testing::RunPendingTasks(); |
| EXPECT_EQ(2, client->NumOnStateChangeCalled()); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| ASSERT_EQ(Result::kOk, consumer->BeginRead(&buffer, &available)); |
| ASSERT_EQ(5u, available); |
| EXPECT_EQ("hello", String(buffer, available)); |
| ASSERT_EQ(Result::kOk, consumer->EndRead(available)); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_EQ(Result::kDone, consumer->BeginRead(&buffer, &available)); |
| EXPECT_EQ(2, client->NumOnStateChangeCalled()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, DrainAsBlobDataHandle) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| |
| scoped_refptr<BlobDataHandle> result = consumer->DrainAsBlobDataHandle( |
| BytesConsumer::BlobSizePolicy::kDisallowBlobWithInvalidSize); |
| ASSERT_TRUE(result); |
| EXPECT_FALSE(consumer->DrainAsBlobDataHandle( |
| BytesConsumer::BlobSizePolicy::kDisallowBlobWithInvalidSize)); |
| EXPECT_EQ(12345u, result->size()); |
| EXPECT_EQ(PublicState::kClosed, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, DrainAsBlobDataHandle_2) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), -1); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| |
| scoped_refptr<BlobDataHandle> result = consumer->DrainAsBlobDataHandle( |
| BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize); |
| ASSERT_TRUE(result); |
| EXPECT_FALSE(consumer->DrainAsBlobDataHandle( |
| BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize)); |
| EXPECT_EQ(UINT64_MAX, result->size()); |
| EXPECT_EQ(PublicState::kClosed, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, DrainAsBlobDataHandle_3) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), -1); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| |
| EXPECT_FALSE(consumer->DrainAsBlobDataHandle( |
| BytesConsumer::BlobSizePolicy::kDisallowBlobWithInvalidSize)); |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, DrainAsFormData) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| |
| EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| |
| scoped_refptr<EncodedFormData> result = consumer->DrainAsFormData(); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(1u, result->Elements().size()); |
| ASSERT_EQ(FormDataElement::kEncodedBlob, result->Elements()[0].type_); |
| ASSERT_TRUE(result->Elements()[0].optional_blob_data_handle_); |
| EXPECT_EQ(12345u, result->Elements()[0].optional_blob_data_handle_->size()); |
| EXPECT_EQ(blob_data_handle->Uuid(), result->Elements()[0].blob_uuid_); |
| EXPECT_EQ(PublicState::kClosed, consumer->GetPublicState()); |
| EXPECT_FALSE(loader->IsStarted()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, LoaderShouldBeCancelled) { |
| { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| TestThreadableLoader* loader = new TestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(Result::kShouldWait, consumer->BeginRead(&buffer, &available)); |
| EXPECT_TRUE(loader->IsStarted()); |
| loader->SetShouldBeCancelled(); |
| } |
| ThreadState::Current()->CollectAllGarbage(); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, SyncErrorDispatch) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| SyncErrorTestThreadableLoader* loader = new SyncErrorTestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| loader->SetClient(consumer); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(Result::kError, consumer->BeginRead(&buffer, &available)); |
| EXPECT_TRUE(loader->IsStarted()); |
| |
| EXPECT_EQ(0, client->NumOnStateChangeCalled()); |
| EXPECT_EQ(BytesConsumer::PublicState::kErrored, consumer->GetPublicState()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, SyncLoading) { |
| scoped_refptr<BlobDataHandle> blob_data_handle = |
| BlobDataHandle::Create(BlobData::Create(), 12345); |
| SyncLoadingTestThreadableLoader* loader = |
| new SyncLoadingTestThreadableLoader(); |
| BlobBytesConsumer* consumer = BlobBytesConsumer::CreateForTesting( |
| &GetDocument(), blob_data_handle, loader); |
| std::unique_ptr<ReplayingHandle> src = ReplayingHandle::Create(); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kData, "hello, ")); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kWait)); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kData, "world")); |
| src->Add(DataConsumerCommand(DataConsumerCommand::kDone)); |
| loader->SetClient(consumer); |
| loader->SetHandle(std::move(src)); |
| BlobBytesConsumerTestClient* client = new BlobBytesConsumerTestClient(); |
| consumer->SetClient(client); |
| |
| const char* buffer = nullptr; |
| size_t available; |
| ASSERT_EQ(Result::kOk, consumer->BeginRead(&buffer, &available)); |
| EXPECT_TRUE(loader->IsStarted()); |
| ASSERT_EQ(7u, available); |
| EXPECT_EQ("hello, ", String(buffer, available)); |
| |
| EXPECT_EQ(0, client->NumOnStateChangeCalled()); |
| EXPECT_EQ(BytesConsumer::PublicState::kReadableOrWaiting, |
| consumer->GetPublicState()); |
| } |
| |
| TEST_F(BlobBytesConsumerTest, ConstructedFromNullHandle) { |
| BlobBytesConsumer* consumer = new BlobBytesConsumer(&GetDocument(), nullptr); |
| const char* buffer = nullptr; |
| size_t available; |
| EXPECT_EQ(BytesConsumer::PublicState::kClosed, consumer->GetPublicState()); |
| EXPECT_EQ(Result::kDone, consumer->BeginRead(&buffer, &available)); |
| } |
| |
| } // namespace |
| |
| } // namespace blink |