| // 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/loader/ThreadableLoader.h" |
| |
| #include <memory> |
| #include "core/dom/TaskRunnerHelper.h" |
| #include "core/loader/DocumentThreadableLoader.h" |
| #include "core/loader/ThreadableLoaderClient.h" |
| #include "core/loader/ThreadableLoadingContext.h" |
| #include "core/loader/WorkerThreadableLoader.h" |
| #include "core/testing/DummyPageHolder.h" |
| #include "core/workers/WorkerLoaderProxy.h" |
| #include "core/workers/WorkerReportingProxy.h" |
| #include "core/workers/WorkerThreadTestHelper.h" |
| #include "platform/WaitableEvent.h" |
| #include "platform/geometry/IntSize.h" |
| #include "platform/loader/fetch/MemoryCache.h" |
| #include "platform/loader/fetch/ResourceError.h" |
| #include "platform/loader/fetch/ResourceLoaderOptions.h" |
| #include "platform/loader/fetch/ResourceRequest.h" |
| #include "platform/loader/fetch/ResourceResponse.h" |
| #include "platform/loader/fetch/ResourceTimingInfo.h" |
| #include "platform/testing/URLTestHelpers.h" |
| #include "platform/testing/UnitTestHelpers.h" |
| #include "platform/weborigin/KURL.h" |
| #include "platform/weborigin/SecurityOrigin.h" |
| #include "platform/wtf/Assertions.h" |
| #include "platform/wtf/Functional.h" |
| #include "platform/wtf/PtrUtil.h" |
| #include "platform/wtf/RefPtr.h" |
| #include "public/platform/Platform.h" |
| #include "public/platform/WebURLLoadTiming.h" |
| #include "public/platform/WebURLLoaderMockFactory.h" |
| #include "public/platform/WebURLResponse.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| using ::testing::_; |
| using ::testing::InSequence; |
| using ::testing::InvokeWithoutArgs; |
| using ::testing::StrEq; |
| using ::testing::Truly; |
| using Checkpoint = ::testing::StrictMock<::testing::MockFunction<void(int)>>; |
| |
| constexpr char kFileName[] = "fox-null-terminated.html"; |
| |
| class MockThreadableLoaderClient : public ThreadableLoaderClient { |
| public: |
| static std::unique_ptr<MockThreadableLoaderClient> Create() { |
| return WTF::WrapUnique( |
| new ::testing::StrictMock<MockThreadableLoaderClient>); |
| } |
| MOCK_METHOD2(DidSendData, void(unsigned long long, unsigned long long)); |
| MOCK_METHOD3(DidReceiveResponseMock, |
| void(unsigned long, |
| const ResourceResponse&, |
| WebDataConsumerHandle*)); |
| void DidReceiveResponse(unsigned long identifier, |
| const ResourceResponse& response, |
| std::unique_ptr<WebDataConsumerHandle> handle) { |
| DidReceiveResponseMock(identifier, response, handle.get()); |
| } |
| MOCK_METHOD2(DidReceiveData, void(const char*, unsigned)); |
| MOCK_METHOD2(DidReceiveCachedMetadata, void(const char*, int)); |
| MOCK_METHOD2(DidFinishLoading, void(unsigned long, double)); |
| MOCK_METHOD1(DidFail, void(const ResourceError&)); |
| MOCK_METHOD1(DidFailAccessControlCheck, void(const ResourceError&)); |
| MOCK_METHOD0(DidFailRedirectCheck, void()); |
| MOCK_METHOD1(DidReceiveResourceTiming, void(const ResourceTimingInfo&)); |
| MOCK_METHOD1(DidDownloadData, void(int)); |
| |
| protected: |
| MockThreadableLoaderClient() = default; |
| }; |
| |
| bool IsCancellation(const ResourceError& error) { |
| return error.IsCancellation(); |
| } |
| |
| bool IsNotCancellation(const ResourceError& error) { |
| return !error.IsCancellation(); |
| } |
| |
| KURL SuccessURL() { |
| return KURL(KURL(), "http://example.com/success"); |
| } |
| KURL ErrorURL() { |
| return KURL(KURL(), "http://example.com/error"); |
| } |
| KURL RedirectURL() { |
| return KURL(KURL(), "http://example.com/redirect"); |
| } |
| KURL RedirectLoopURL() { |
| return KURL(KURL(), "http://example.com/loop"); |
| } |
| |
| enum ThreadableLoaderToTest { |
| kDocumentThreadableLoaderTest, |
| kWorkerThreadableLoaderTest, |
| }; |
| |
| class ThreadableLoaderTestHelper { |
| public: |
| virtual ~ThreadableLoaderTestHelper() {} |
| |
| virtual void CreateLoader(ThreadableLoaderClient*, |
| CrossOriginRequestPolicy) = 0; |
| virtual void StartLoader(const ResourceRequest&) = 0; |
| virtual void CancelLoader() = 0; |
| virtual void CancelAndClearLoader() = 0; |
| virtual void ClearLoader() = 0; |
| virtual Checkpoint& GetCheckpoint() = 0; |
| virtual void CallCheckpoint(int) = 0; |
| virtual void OnSetUp() = 0; |
| virtual void OnServeRequests() = 0; |
| virtual void OnTearDown() = 0; |
| }; |
| |
| class DocumentThreadableLoaderTestHelper : public ThreadableLoaderTestHelper { |
| public: |
| DocumentThreadableLoaderTestHelper() |
| : dummy_page_holder_(DummyPageHolder::Create(IntSize(1, 1))) {} |
| |
| void CreateLoader( |
| ThreadableLoaderClient* client, |
| CrossOriginRequestPolicy cross_origin_request_policy) override { |
| ThreadableLoaderOptions options; |
| options.cross_origin_request_policy = cross_origin_request_policy; |
| ResourceLoaderOptions resource_loader_options; |
| loader_ = DocumentThreadableLoader::Create( |
| *ThreadableLoadingContext::Create(GetDocument()), client, options, |
| resource_loader_options); |
| } |
| |
| void StartLoader(const ResourceRequest& request) override { |
| loader_->Start(request); |
| } |
| |
| void CancelLoader() override { loader_->Cancel(); } |
| void CancelAndClearLoader() override { |
| loader_->Cancel(); |
| loader_ = nullptr; |
| } |
| void ClearLoader() override { loader_ = nullptr; } |
| Checkpoint& GetCheckpoint() override { return checkpoint_; } |
| void CallCheckpoint(int n) override { checkpoint_.Call(n); } |
| |
| void OnSetUp() override {} |
| |
| void OnServeRequests() override {} |
| |
| void OnTearDown() override { |
| if (loader_) { |
| loader_->Cancel(); |
| loader_ = nullptr; |
| } |
| } |
| |
| private: |
| Document& GetDocument() { return dummy_page_holder_->GetDocument(); } |
| |
| std::unique_ptr<DummyPageHolder> dummy_page_holder_; |
| Checkpoint checkpoint_; |
| Persistent<DocumentThreadableLoader> loader_; |
| }; |
| |
| class WorkerThreadableLoaderTestHelper : public ThreadableLoaderTestHelper, |
| public WorkerLoaderProxyProvider { |
| public: |
| WorkerThreadableLoaderTestHelper() |
| : dummy_page_holder_(DummyPageHolder::Create(IntSize(1, 1))) {} |
| |
| void CreateLoader( |
| ThreadableLoaderClient* client, |
| CrossOriginRequestPolicy cross_origin_request_policy) override { |
| std::unique_ptr<WaitableEvent> completion_event = |
| WTF::MakeUnique<WaitableEvent>(); |
| PostTaskToWorkerGlobalScope( |
| BLINK_FROM_HERE, |
| CrossThreadBind(&WorkerThreadableLoaderTestHelper::WorkerCreateLoader, |
| CrossThreadUnretained(this), |
| CrossThreadUnretained(client), |
| CrossThreadUnretained(completion_event.get()), |
| cross_origin_request_policy)); |
| completion_event->Wait(); |
| } |
| |
| void StartLoader(const ResourceRequest& request) override { |
| std::unique_ptr<WaitableEvent> completion_event = |
| WTF::MakeUnique<WaitableEvent>(); |
| PostTaskToWorkerGlobalScope( |
| BLINK_FROM_HERE, |
| CrossThreadBind(&WorkerThreadableLoaderTestHelper::WorkerStartLoader, |
| CrossThreadUnretained(this), |
| CrossThreadUnretained(completion_event.get()), |
| request)); |
| completion_event->Wait(); |
| } |
| |
| // Must be called on the worker thread. |
| void CancelLoader() override { |
| DCHECK(worker_thread_); |
| DCHECK(worker_thread_->IsCurrentThread()); |
| loader_->Cancel(); |
| } |
| |
| void CancelAndClearLoader() override { |
| DCHECK(worker_thread_); |
| DCHECK(worker_thread_->IsCurrentThread()); |
| loader_->Cancel(); |
| loader_ = nullptr; |
| } |
| |
| // Must be called on the worker thread. |
| void ClearLoader() override { |
| DCHECK(worker_thread_); |
| DCHECK(worker_thread_->IsCurrentThread()); |
| loader_ = nullptr; |
| } |
| |
| Checkpoint& GetCheckpoint() override { return checkpoint_; } |
| |
| void CallCheckpoint(int n) override { |
| testing::RunPendingTasks(); |
| |
| std::unique_ptr<WaitableEvent> completion_event = |
| WTF::MakeUnique<WaitableEvent>(); |
| PostTaskToWorkerGlobalScope( |
| BLINK_FROM_HERE, |
| CrossThreadBind(&WorkerThreadableLoaderTestHelper::WorkerCallCheckpoint, |
| CrossThreadUnretained(this), |
| CrossThreadUnretained(completion_event.get()), n)); |
| completion_event->Wait(); |
| } |
| |
| void OnSetUp() override { |
| reporting_proxy_ = WTF::MakeUnique<WorkerReportingProxy>(); |
| security_origin_ = GetDocument().GetSecurityOrigin(); |
| parent_frame_task_runners_ = |
| ParentFrameTaskRunners::Create(&dummy_page_holder_->GetFrame()); |
| worker_thread_ = |
| WTF::WrapUnique(new WorkerThreadForTest(this, *reporting_proxy_)); |
| loading_context_ = ThreadableLoadingContext::Create(GetDocument()); |
| |
| worker_thread_->StartWithSourceCode(security_origin_.Get(), |
| "//fake source code", |
| parent_frame_task_runners_.Get()); |
| worker_thread_->WaitForInit(); |
| } |
| |
| void OnServeRequests() override { testing::RunPendingTasks(); } |
| |
| void OnTearDown() override { |
| PostTaskToWorkerGlobalScope( |
| BLINK_FROM_HERE, |
| CrossThreadBind(&WorkerThreadableLoaderTestHelper::ClearLoader, |
| CrossThreadUnretained(this))); |
| WaitableEvent event; |
| PostTaskToWorkerGlobalScope( |
| BLINK_FROM_HERE, |
| CrossThreadBind(&WaitableEvent::Signal, CrossThreadUnretained(&event))); |
| event.Wait(); |
| worker_thread_->TerminateAndWait(); |
| |
| // Needed to clean up the things on the main thread side and |
| // avoid Resource leaks. |
| testing::RunPendingTasks(); |
| |
| worker_thread_->GetWorkerLoaderProxy()->DetachProvider(this); |
| } |
| |
| private: |
| Document& GetDocument() { return dummy_page_holder_->GetDocument(); } |
| |
| void WorkerCreateLoader( |
| ThreadableLoaderClient* client, |
| WaitableEvent* event, |
| CrossOriginRequestPolicy cross_origin_request_policy) { |
| DCHECK(worker_thread_); |
| DCHECK(worker_thread_->IsCurrentThread()); |
| |
| ThreadableLoaderOptions options; |
| options.cross_origin_request_policy = cross_origin_request_policy; |
| ResourceLoaderOptions resource_loader_options; |
| |
| // Ensure that WorkerThreadableLoader is created. |
| // ThreadableLoader::create() determines whether it should create |
| // a DocumentThreadableLoader or WorkerThreadableLoader based on |
| // isWorkerGlobalScope(). |
| DCHECK(worker_thread_->GlobalScope()->IsWorkerGlobalScope()); |
| |
| loader_ = ThreadableLoader::Create(*worker_thread_->GlobalScope(), client, |
| options, resource_loader_options); |
| DCHECK(loader_); |
| event->Signal(); |
| } |
| |
| void WorkerStartLoader( |
| WaitableEvent* event, |
| std::unique_ptr<CrossThreadResourceRequestData> request_data) { |
| DCHECK(worker_thread_); |
| DCHECK(worker_thread_->IsCurrentThread()); |
| |
| ResourceRequest request(request_data.get()); |
| loader_->Start(request); |
| event->Signal(); |
| } |
| |
| void WorkerCallCheckpoint(WaitableEvent* event, int n) { |
| DCHECK(worker_thread_); |
| DCHECK(worker_thread_->IsCurrentThread()); |
| checkpoint_.Call(n); |
| event->Signal(); |
| } |
| |
| // WorkerLoaderProxyProvider methods. |
| void PostTaskToLoader( |
| const WebTraceLocation& location, |
| std::unique_ptr<WTF::CrossThreadClosure> task) override { |
| DCHECK(worker_thread_); |
| DCHECK(worker_thread_->IsCurrentThread()); |
| parent_frame_task_runners_->Get(TaskType::kNetworking) |
| ->PostTask(BLINK_FROM_HERE, std::move(task)); |
| } |
| |
| void PostTaskToWorkerGlobalScope( |
| const WebTraceLocation& location, |
| std::unique_ptr<WTF::CrossThreadClosure> task) override { |
| DCHECK(worker_thread_); |
| TaskRunnerHelper::Get(TaskType::kNetworking, worker_thread_.get()) |
| ->PostTask(location, std::move(task)); |
| } |
| |
| ThreadableLoadingContext* GetThreadableLoadingContext() override { |
| return loading_context_.Get(); |
| } |
| |
| RefPtr<SecurityOrigin> security_origin_; |
| std::unique_ptr<WorkerReportingProxy> reporting_proxy_; |
| std::unique_ptr<WorkerThreadForTest> worker_thread_; |
| |
| std::unique_ptr<DummyPageHolder> dummy_page_holder_; |
| // Accessed cross-thread when worker thread posts tasks to the parent. |
| CrossThreadPersistent<ParentFrameTaskRunners> parent_frame_task_runners_; |
| Checkpoint checkpoint_; |
| // |m_loader| must be touched only from the worker thread only. |
| CrossThreadPersistent<ThreadableLoader> loader_; |
| |
| Persistent<ThreadableLoadingContext> loading_context_; |
| }; |
| |
| class ThreadableLoaderTest |
| : public ::testing::TestWithParam<ThreadableLoaderToTest> { |
| public: |
| ThreadableLoaderTest() { |
| switch (GetParam()) { |
| case kDocumentThreadableLoaderTest: |
| helper_ = WTF::WrapUnique(new DocumentThreadableLoaderTestHelper); |
| break; |
| case kWorkerThreadableLoaderTest: |
| helper_ = WTF::WrapUnique(new WorkerThreadableLoaderTestHelper()); |
| break; |
| } |
| } |
| |
| void StartLoader(const KURL& url) { |
| ResourceRequest request(url); |
| request.SetRequestContext(WebURLRequest::kRequestContextObject); |
| helper_->StartLoader(request); |
| } |
| |
| void CancelLoader() { helper_->CancelLoader(); } |
| void CancelAndClearLoader() { helper_->CancelAndClearLoader(); } |
| void ClearLoader() { helper_->ClearLoader(); } |
| Checkpoint& GetCheckpoint() { return helper_->GetCheckpoint(); } |
| void CallCheckpoint(int n) { helper_->CallCheckpoint(n); } |
| |
| void ServeRequests() { |
| helper_->OnServeRequests(); |
| Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); |
| } |
| |
| void CreateLoader(CrossOriginRequestPolicy cross_origin_request_policy = |
| kAllowCrossOriginRequests) { |
| helper_->CreateLoader(Client(), cross_origin_request_policy); |
| } |
| |
| MockThreadableLoaderClient* Client() const { return client_.get(); } |
| |
| private: |
| void SetUp() override { |
| SetUpSuccessURL(); |
| SetUpErrorURL(); |
| SetUpRedirectURL(); |
| SetUpRedirectLoopURL(); |
| |
| client_ = MockThreadableLoaderClient::Create(); |
| helper_->OnSetUp(); |
| } |
| |
| void TearDown() override { |
| helper_->OnTearDown(); |
| Platform::Current() |
| ->GetURLLoaderMockFactory() |
| ->UnregisterAllURLsAndClearMemoryCache(); |
| client_.reset(); |
| } |
| |
| void SetUpSuccessURL() { |
| URLTestHelpers::RegisterMockedURLLoad( |
| SuccessURL(), testing::WebTestDataPath(kFileName), "text/html"); |
| } |
| |
| void SetUpErrorURL() { |
| URLTestHelpers::RegisterMockedErrorURLLoad(ErrorURL()); |
| } |
| |
| void SetUpRedirectURL() { |
| KURL url = RedirectURL(); |
| |
| WebURLLoadTiming timing; |
| timing.Initialize(); |
| |
| WebURLResponse response; |
| response.SetURL(url); |
| response.SetHTTPStatusCode(301); |
| response.SetLoadTiming(timing); |
| response.AddHTTPHeaderField("Location", SuccessURL().GetString()); |
| response.AddHTTPHeaderField("Access-Control-Allow-Origin", "null"); |
| |
| URLTestHelpers::RegisterMockedURLLoadWithCustomResponse( |
| url, testing::WebTestDataPath(kFileName), response); |
| } |
| |
| void SetUpRedirectLoopURL() { |
| KURL url = RedirectLoopURL(); |
| |
| WebURLLoadTiming timing; |
| timing.Initialize(); |
| |
| WebURLResponse response; |
| response.SetURL(url); |
| response.SetHTTPStatusCode(301); |
| response.SetLoadTiming(timing); |
| response.AddHTTPHeaderField("Location", RedirectLoopURL().GetString()); |
| response.AddHTTPHeaderField("Access-Control-Allow-Origin", "null"); |
| |
| URLTestHelpers::RegisterMockedURLLoadWithCustomResponse( |
| url, testing::WebTestDataPath(kFileName), response); |
| } |
| |
| std::unique_ptr<MockThreadableLoaderClient> client_; |
| std::unique_ptr<ThreadableLoaderTestHelper> helper_; |
| }; |
| |
| INSTANTIATE_TEST_CASE_P(Document, |
| ThreadableLoaderTest, |
| ::testing::Values(kDocumentThreadableLoaderTest)); |
| |
| INSTANTIATE_TEST_CASE_P(Worker, |
| ThreadableLoaderTest, |
| ::testing::Values(kWorkerThreadableLoaderTest)); |
| |
| TEST_P(ThreadableLoaderTest, StartAndStop) {} |
| |
| TEST_P(ThreadableLoaderTest, CancelAfterStart) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| EXPECT_CALL(*Client(), DidFail(Truly(IsCancellation))); |
| EXPECT_CALL(GetCheckpoint(), Call(3)); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| CallCheckpoint(3); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelAndClearAfterStart) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)) |
| .WillOnce( |
| InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelAndClearLoader)); |
| EXPECT_CALL(*Client(), DidFail(Truly(IsCancellation))); |
| EXPECT_CALL(GetCheckpoint(), Call(3)); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| CallCheckpoint(3); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelInDidReceiveResponse) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| EXPECT_CALL(*Client(), DidFail(Truly(IsCancellation))); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelAndClearInDidReceiveResponse) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)) |
| .WillOnce( |
| InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelAndClearLoader)); |
| EXPECT_CALL(*Client(), DidFail(Truly(IsCancellation))); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelInDidReceiveData) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidReceiveData(_, _)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| EXPECT_CALL(*Client(), DidFail(Truly(IsCancellation))); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelAndClearInDidReceiveData) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidReceiveData(_, _)) |
| .WillOnce( |
| InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelAndClearLoader)); |
| EXPECT_CALL(*Client(), DidFail(Truly(IsCancellation))); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, DidFinishLoading) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidReceiveData(StrEq("fox"), 4)); |
| // We expect didReceiveResourceTiming() calls in DocumentThreadableLoader; |
| // it's used to connect DocumentThreadableLoader to WorkerThreadableLoader, |
| // not to ThreadableLoaderClient. |
| EXPECT_CALL(*Client(), DidReceiveResourceTiming(_)); |
| EXPECT_CALL(*Client(), DidFinishLoading(_, _)); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelInDidFinishLoading) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidReceiveData(_, _)); |
| EXPECT_CALL(*Client(), DidReceiveResourceTiming(_)); |
| EXPECT_CALL(*Client(), DidFinishLoading(_, _)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, ClearInDidFinishLoading) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidReceiveData(_, _)); |
| EXPECT_CALL(*Client(), DidReceiveResourceTiming(_)); |
| EXPECT_CALL(*Client(), DidFinishLoading(_, _)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::ClearLoader)); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, DidFail) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidFail(Truly(IsNotCancellation))); |
| |
| StartLoader(ErrorURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelInDidFail) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidFail(_)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| |
| StartLoader(ErrorURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, ClearInDidFail) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidFail(_)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::ClearLoader)); |
| |
| StartLoader(ErrorURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, DidFailInStart) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kDenyCrossOriginRequests); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(*Client(), |
| DidFail(ResourceError( |
| kErrorDomainBlinkInternal, 0, ErrorURL().GetString(), |
| "Cross origin requests are not supported."))); |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| |
| StartLoader(ErrorURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelInDidFailInStart) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kDenyCrossOriginRequests); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(*Client(), DidFail(_)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| |
| StartLoader(ErrorURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, ClearInDidFailInStart) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kDenyCrossOriginRequests); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(*Client(), DidFail(_)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::ClearLoader)); |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| |
| StartLoader(ErrorURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, DidFailAccessControlCheck) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kUseAccessControl); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL( |
| *Client(), |
| DidFailAccessControlCheck(ResourceError( |
| kErrorDomainBlinkInternal, 0, SuccessURL().GetString(), |
| "No 'Access-Control-Allow-Origin' header is present on the requested " |
| "resource. Origin 'null' is therefore not allowed access."))); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelInDidFailAccessControlCheck) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kUseAccessControl); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidFailAccessControlCheck(_)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, ClearInDidFailAccessControlCheck) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kUseAccessControl); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidFailAccessControlCheck(_)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::ClearLoader)); |
| |
| StartLoader(SuccessURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, RedirectDidFinishLoading) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidReceiveData(StrEq("fox"), 4)); |
| EXPECT_CALL(*Client(), DidReceiveResourceTiming(_)); |
| EXPECT_CALL(*Client(), DidFinishLoading(_, _)); |
| |
| StartLoader(RedirectURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelInRedirectDidFinishLoading) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidReceiveData(StrEq("fox"), 4)); |
| EXPECT_CALL(*Client(), DidReceiveResourceTiming(_)); |
| EXPECT_CALL(*Client(), DidFinishLoading(_, _)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| |
| StartLoader(RedirectURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, ClearInRedirectDidFinishLoading) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); |
| EXPECT_CALL(*Client(), DidReceiveData(StrEq("fox"), 4)); |
| EXPECT_CALL(*Client(), DidReceiveResourceTiming(_)); |
| EXPECT_CALL(*Client(), DidFinishLoading(_, _)) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::ClearLoader)); |
| |
| StartLoader(RedirectURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, DidFailRedirectCheck) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kUseAccessControl); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidFailRedirectCheck()); |
| |
| StartLoader(RedirectLoopURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, CancelInDidFailRedirectCheck) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kUseAccessControl); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidFailRedirectCheck()) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); |
| |
| StartLoader(RedirectLoopURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| TEST_P(ThreadableLoaderTest, ClearInDidFailRedirectCheck) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kUseAccessControl); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| EXPECT_CALL(*Client(), DidFailRedirectCheck()) |
| .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::ClearLoader)); |
| |
| StartLoader(RedirectLoopURL()); |
| CallCheckpoint(2); |
| ServeRequests(); |
| } |
| |
| // This test case checks blink doesn't crash even when the response arrives |
| // synchronously. |
| TEST_P(ThreadableLoaderTest, GetResponseSynchronously) { |
| InSequence s; |
| EXPECT_CALL(GetCheckpoint(), Call(1)); |
| CreateLoader(kUseAccessControl); |
| CallCheckpoint(1); |
| |
| EXPECT_CALL(*Client(), DidFailAccessControlCheck(_)); |
| EXPECT_CALL(GetCheckpoint(), Call(2)); |
| |
| // Currently didFailAccessControlCheck is dispatched synchronously. This |
| // test is not saying that didFailAccessControlCheck should be dispatched |
| // synchronously, but is saying that even when a response is served |
| // synchronously it should not lead to a crash. |
| StartLoader(KURL(KURL(), "about:blank")); |
| CallCheckpoint(2); |
| } |
| |
| } // namespace |
| |
| } // namespace blink |