blob: 940c8db590bce2b3f37da36e739ce7640806e8db [file] [log] [blame]
// 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 "third_party/blink/renderer/core/loader/resource/font_resource.h"
#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/renderer/core/css/css_font_face_src_value.h"
#include "third_party/blink/renderer/core/loader/resource/mock_font_resource_client.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
#include "third_party/blink/renderer/platform/loader/testing/mock_resource_client.h"
#include "third_party/blink/renderer/platform/loader/testing/test_loader_factory.h"
#include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
class FontResourceTest : public testing::Test {
public:
void TearDown() override {
Platform::Current()
->GetURLLoaderMockFactory()
->UnregisterAllURLsAndClearMemoryCache();
}
};
class CacheAwareFontResourceTest : public FontResourceTest {
public:
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(
features::kWebFontsCacheAwareTimeoutAdaption);
FontResourceTest::SetUp();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
// Tests if ResourceFetcher works fine with FontResource that requires defered
// loading supports.
TEST_F(FontResourceTest,
ResourceFetcherRevalidateDeferedResourceFromTwoInitiators) {
KURL url("http://127.0.0.1:8000/font.woff");
ResourceResponse response(url);
response.SetHTTPStatusCode(200);
response.SetHTTPHeaderField(http_names::kETag, "1234567890");
Platform::Current()->GetURLLoaderMockFactory()->RegisterURL(
url, WrappedResourceResponse(response), "");
MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
*properties, context, base::MakeRefCounted<scheduler::FakeTaskRunner>(),
MakeGarbageCollected<TestLoaderFactory>()));
// Fetch to cache a resource.
ResourceRequest request1(url);
FetchParameters fetch_params1(request1);
Resource* resource1 = FontResource::Fetch(fetch_params1, fetcher, nullptr);
ASSERT_FALSE(resource1->ErrorOccurred());
fetcher->StartLoad(resource1);
Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
EXPECT_TRUE(resource1->IsLoaded());
EXPECT_FALSE(resource1->ErrorOccurred());
// Set the context as it is on reloads.
properties->SetIsLoadComplete(true);
// Revalidate the resource.
ResourceRequest request2(url);
request2.SetCacheMode(mojom::FetchCacheMode::kValidateCache);
FetchParameters fetch_params2(request2);
Resource* resource2 = FontResource::Fetch(fetch_params2, fetcher, nullptr);
ASSERT_FALSE(resource2->ErrorOccurred());
EXPECT_EQ(resource1, resource2);
EXPECT_TRUE(resource2->IsCacheValidator());
EXPECT_TRUE(resource2->StillNeedsLoad());
// Fetch the same resource again before actual load operation starts.
ResourceRequest request3(url);
request3.SetCacheMode(mojom::FetchCacheMode::kValidateCache);
FetchParameters fetch_params3(request3);
Resource* resource3 = FontResource::Fetch(fetch_params3, fetcher, nullptr);
ASSERT_FALSE(resource3->ErrorOccurred());
EXPECT_EQ(resource2, resource3);
EXPECT_TRUE(resource3->IsCacheValidator());
EXPECT_TRUE(resource3->StillNeedsLoad());
// StartLoad() can be called from any initiator. Here, call it from the
// latter.
fetcher->StartLoad(resource3);
Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
EXPECT_TRUE(resource3->IsLoaded());
EXPECT_FALSE(resource3->ErrorOccurred());
EXPECT_TRUE(resource2->IsLoaded());
EXPECT_FALSE(resource2->ErrorOccurred());
GetMemoryCache()->Remove(resource1);
}
// Tests if cache-aware font loading works correctly.
TEST_F(CacheAwareFontResourceTest, CacheAwareFontLoading) {
KURL url("http://127.0.0.1:8000/font.woff");
ResourceResponse response(url);
response.SetHTTPStatusCode(200);
Platform::Current()->GetURLLoaderMockFactory()->RegisterURL(
url, WrappedResourceResponse(response), "");
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create(IntSize(800, 600));
Document& document = dummy_page_holder->GetDocument();
ResourceFetcher* fetcher = document.Fetcher();
CSSFontFaceSrcValue* src_value = CSSFontFaceSrcValue::Create(
url.GetString(), url.GetString(),
Referrer(document.Url(), document.GetReferrerPolicy()),
kDoNotCheckContentSecurityPolicy);
// Route font requests in this test through CSSFontFaceSrcValue::Fetch
// instead of calling FontResource::Fetch directly. CSSFontFaceSrcValue
// requests a FontResource only once, and skips calling FontResource::Fetch
// on future CSSFontFaceSrcValue::Fetch calls. This tests wants to ensure
// correct behavior in the case where we reuse a FontResource without it being
// a "cache hit" in ResourceFetcher's view.
Persistent<MockFontResourceClient> client =
MakeGarbageCollected<MockFontResourceClient>();
FontResource& resource = src_value->Fetch(&document, client);
fetcher->StartLoad(&resource);
EXPECT_TRUE(resource.Loader()->IsCacheAwareLoadingActivated());
resource.load_limit_state_ = FontResource::kUnderLimit;
// FontResource callbacks should be blocked during cache-aware loading.
resource.FontLoadShortLimitCallback();
EXPECT_FALSE(client->FontLoadShortLimitExceededCalled());
// Fail first request as disk cache miss.
resource.Loader()->HandleError(ResourceError::CacheMissError(url));
// Once cache miss error returns, previously blocked callbacks should be
// called immediately.
EXPECT_FALSE(resource.Loader()->IsCacheAwareLoadingActivated());
EXPECT_TRUE(client->FontLoadShortLimitExceededCalled());
EXPECT_FALSE(client->FontLoadLongLimitExceededCalled());
// Add client now, FontLoadShortLimitExceeded() should be called.
Persistent<MockFontResourceClient> client2 =
MakeGarbageCollected<MockFontResourceClient>();
FontResource& resource2 = src_value->Fetch(&document, client2);
EXPECT_EQ(&resource, &resource2);
EXPECT_TRUE(client2->FontLoadShortLimitExceededCalled());
EXPECT_FALSE(client2->FontLoadLongLimitExceededCalled());
// FontResource callbacks are not blocked now.
resource.FontLoadLongLimitCallback();
EXPECT_TRUE(client->FontLoadLongLimitExceededCalled());
// Add client now, both callbacks should be called.
Persistent<MockFontResourceClient> client3 =
MakeGarbageCollected<MockFontResourceClient>();
FontResource& resource3 = src_value->Fetch(&document, client3);
EXPECT_EQ(&resource, &resource3);
EXPECT_TRUE(client3->FontLoadShortLimitExceededCalled());
EXPECT_TRUE(client3->FontLoadLongLimitExceededCalled());
Platform::Current()->GetURLLoaderMockFactory()->ServeAsynchronousRequests();
GetMemoryCache()->Remove(&resource);
}
} // namespace blink