blob: 0a6da766fed75cd3004ec9893037bb93acb754c5 [file] [log] [blame]
// Copyright 2018 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 "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
namespace blink {
class ResourceLoaderDefersLoadingTest : public testing::Test {
public:
using ProcessCodeCacheRequestCallback =
base::RepeatingCallback<void(CodeCacheLoader::FetchCodeCacheCallback)>;
class TestingPlatformSupportWithMockCodeCacheLoader;
class TestCodeCacheLoader;
class TestWebURLLoaderFactory;
class TestWebURLLoader;
ResourceLoaderDefersLoadingTest();
void SetUp() override {
context_ = MakeGarbageCollected<MockFetchContext>(
MockFetchContext::kShouldLoadNewResource);
}
void SaveCodeCacheCallback(CodeCacheLoader::FetchCodeCacheCallback callback) {
// Store the callback to send back a response.
code_cache_response_callback_ = std::move(callback);
}
CodeCacheLoader::FetchCodeCacheCallback code_cache_response_callback_;
// Passed to TestWebURLLoader (via |platform_|) and updated when its
// SetDefersLoading method is called.
bool web_url_loader_defers_ = false;
Persistent<MockFetchContext> context_;
const KURL test_url_;
ScopedTestingPlatformSupport<
ResourceLoaderDefersLoadingTest::
TestingPlatformSupportWithMockCodeCacheLoader,
bool*>
platform_;
};
// A mock code cache loader that calls the processing function whenever it
// receives fetch requests.
class ResourceLoaderDefersLoadingTest::TestCodeCacheLoader
: public CodeCacheLoader {
public:
explicit TestCodeCacheLoader(ProcessCodeCacheRequestCallback callback)
: process_request_(callback) {}
~TestCodeCacheLoader() override = default;
// CodeCacheLoader methods:
void FetchFromCodeCacheSynchronously(
const GURL& url,
base::Time* response_time_out,
std::vector<uint8_t>* data_out) override {}
void FetchFromCodeCache(
blink::mojom::CodeCacheType cache_type,
const GURL& url,
CodeCacheLoader::FetchCodeCacheCallback callback) override {
process_request_.Run(std::move(callback));
}
private:
ProcessCodeCacheRequestCallback process_request_;
};
// A mock WebURLLoader to know the status of defers flag.
class ResourceLoaderDefersLoadingTest::TestWebURLLoader final
: public WebURLLoader {
public:
explicit TestWebURLLoader(bool* const defers_flag_ptr)
: defers_flag_ptr_(defers_flag_ptr) {}
~TestWebURLLoader() override = default;
void LoadSynchronously(const WebURLRequest&,
WebURLLoaderClient*,
WebURLResponse&,
base::Optional<WebURLError>&,
WebData&,
int64_t& encoded_data_length,
int64_t& encoded_body_length,
WebBlobInfo& downloaded_blob) override {
NOTREACHED();
}
void LoadAsynchronously(const WebURLRequest&, WebURLLoaderClient*) override {}
void Cancel() override {}
void SetDefersLoading(bool defers) override { *defers_flag_ptr_ = defers; }
void DidChangePriority(WebURLRequest::Priority, int) override {
NOTREACHED();
}
private:
// Points to |ResourceLoaderDefersLoadingTest::web_url_loader_defers_|.
bool* const defers_flag_ptr_;
};
// Mock WebURLLoaderFactory.
class ResourceLoaderDefersLoadingTest::TestWebURLLoaderFactory final
: public WebURLLoaderFactory {
public:
explicit TestWebURLLoaderFactory(bool* const defers_flag)
: defers_flag_(defers_flag) {}
std::unique_ptr<WebURLLoader> CreateURLLoader(
const WebURLRequest& request,
std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>) override {
return std::make_unique<TestWebURLLoader>(defers_flag_);
}
private:
// Points to |ResourceLoaderDefersLoadingTest::web_url_loader_defers_|.
bool* const defers_flag_;
};
// Mock TestPlatform to create the specific WebURLLoaderFactory and
// CodeCacheLoader required for the tests.
class ResourceLoaderDefersLoadingTest::
TestingPlatformSupportWithMockCodeCacheLoader
: public TestingPlatformSupportWithMockScheduler {
public:
TestingPlatformSupportWithMockCodeCacheLoader(bool* const defers_flag)
: defers_flag_(defers_flag) {}
std::unique_ptr<CodeCacheLoader> CreateCodeCacheLoader() override {
return std::make_unique<TestCodeCacheLoader>(process_code_cache_request_);
}
std::unique_ptr<WebURLLoaderFactory> CreateDefaultURLLoaderFactory()
override {
return std::make_unique<TestWebURLLoaderFactory>(defers_flag_);
}
void SetCodeCacheProcessFunction(ProcessCodeCacheRequestCallback callback) {
process_code_cache_request_ = callback;
}
private:
ProcessCodeCacheRequestCallback process_code_cache_request_;
// Points to |ResourceLoaderDefersLoadingTest::web_url_loader_defers_|.
bool* const defers_flag_;
};
ResourceLoaderDefersLoadingTest::ResourceLoaderDefersLoadingTest()
: test_url_("http://example.com/"), platform_(&web_url_loader_defers_) {
// Saves the callback to control when the response is sent from
// the code cache loader.
platform_->SetCodeCacheProcessFunction(base::BindRepeating(
&ResourceLoaderDefersLoadingTest::SaveCodeCacheCallback,
base::Unretained(this)));
}
TEST_F(ResourceLoaderDefersLoadingTest, CodeCacheFetchCheckDefers) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
auto* fetcher = MakeGarbageCollected<ResourceFetcher>(*properties, context_);
ResourceRequest request;
request.SetURL(test_url_);
request.SetRequestContext(mojom::RequestContextType::FRAME);
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
nullptr, SubstituteData(),
CreateUniqueIdentifier());
// After code cache fetch it should have deferred WebURLLoader.
DCHECK(web_url_loader_defers_);
DCHECK(resource);
std::move(code_cache_response_callback_)
.Run(base::Time(), std::vector<uint8_t>());
// Once the response is received it should be reset.
DCHECK(!web_url_loader_defers_);
}
TEST_F(ResourceLoaderDefersLoadingTest, CodeCacheFetchSyncReturn) {
platform_->SetCodeCacheProcessFunction(
base::BindRepeating([](CodeCacheLoader::FetchCodeCacheCallback callback) {
std::move(callback).Run(base::Time(), std::vector<uint8_t>());
}));
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
auto* fetcher = MakeGarbageCollected<ResourceFetcher>(*properties, context_);
ResourceRequest request;
request.SetURL(test_url_);
request.SetRequestContext(mojom::RequestContextType::FRAME);
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
nullptr, SubstituteData(),
CreateUniqueIdentifier());
DCHECK(resource);
// The callback would be called so it should not be deferred.
DCHECK(!web_url_loader_defers_);
}
TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToFalse) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
auto* fetcher = MakeGarbageCollected<ResourceFetcher>(*properties, context_);
ResourceRequest request;
request.SetURL(test_url_);
request.SetRequestContext(mojom::RequestContextType::FRAME);
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
nullptr, SubstituteData(),
CreateUniqueIdentifier());
DCHECK(web_url_loader_defers_);
// Change Defers loading to false. This should not be sent to
// WebURLLoader since a code cache request is still pending.
ResourceLoader* loader = resource->Loader();
loader->SetDefersLoading(false);
DCHECK(web_url_loader_defers_);
}
TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersToTrue) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
auto* fetcher = MakeGarbageCollected<ResourceFetcher>(*properties, context_);
ResourceRequest request;
request.SetURL(test_url_);
request.SetRequestContext(mojom::RequestContextType::FRAME);
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
nullptr, SubstituteData(),
CreateUniqueIdentifier());
DCHECK(web_url_loader_defers_);
ResourceLoader* loader = resource->Loader();
loader->SetDefersLoading(true);
DCHECK(web_url_loader_defers_);
std::move(code_cache_response_callback_)
.Run(base::Time(), std::vector<uint8_t>());
// Since it was requested to be deferred, it should be reset to the
// correct value.
DCHECK(web_url_loader_defers_);
}
TEST_F(ResourceLoaderDefersLoadingTest, ChangeDefersMultipleTimes) {
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
auto* fetcher = MakeGarbageCollected<ResourceFetcher>(*properties, context_);
ResourceRequest request;
request.SetURL(test_url_);
request.SetRequestContext(mojom::RequestContextType::FRAME);
request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
FetchParameters fetch_parameters(request);
Resource* resource = RawResource::FetchMainResource(fetch_parameters, fetcher,
nullptr, SubstituteData(),
CreateUniqueIdentifier());
DCHECK(web_url_loader_defers_);
ResourceLoader* loader = resource->Loader();
loader->SetDefersLoading(true);
DCHECK(web_url_loader_defers_);
loader->SetDefersLoading(false);
DCHECK(web_url_loader_defers_);
std::move(code_cache_response_callback_)
.Run(base::Time(), std::vector<uint8_t>());
DCHECK(!web_url_loader_defers_);
}
} // namespace blink