blob: 460abdd0a727e05bcd10916fb834521001abf26c [file] [log] [blame]
// Copyright 2021 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 "chrome/browser/preloading/prefetch/prefetch_proxy/prefetch_container.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "chrome/browser/preloading/prefetch/prefetch_proxy/prefetch_proxy_prefetch_status.h"
#include "chrome/browser/preloading/prefetch/prefetch_proxy/prefetched_mainframe_response_container.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "content/public/browser/storage_partition.h"
#include "net/base/isolation_info.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
class PrefetchContainerTest : public ChromeRenderViewHostTestHarness {
public:
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
profile()
->GetDefaultStoragePartition()
->GetNetworkContext()
->GetCookieManager(cookie_manager_.BindNewPipeAndPassReceiver());
}
bool SetCookie(const GURL& url, const std::string& value) {
bool result = false;
base::RunLoop run_loop;
std::unique_ptr<net::CanonicalCookie> cookie(net::CanonicalCookie::Create(
url, value, base::Time::Now(), /*server_time=*/absl::nullopt,
/*cookie_partition_key=*/absl::nullopt));
EXPECT_TRUE(cookie.get());
EXPECT_TRUE(cookie->IsHostCookie());
net::CookieOptions options;
options.set_include_httponly();
options.set_same_site_cookie_context(
net::CookieOptions::SameSiteCookieContext::MakeInclusive());
cookie_manager_->SetCanonicalCookie(
*cookie.get(), url, options,
base::BindOnce(
[](bool* result, base::RunLoop* run_loop,
net::CookieAccessResult set_cookie_access_result) {
*result = set_cookie_access_result.status.IsInclude();
run_loop->Quit();
},
&result, &run_loop));
// This will run until the cookie is set.
run_loop.Run();
// This will run until the cookie listener gets the cookie change.
base::RunLoop().RunUntilIdle();
return result;
}
network::mojom::CookieManager* cookie_manager() {
return cookie_manager_.get();
}
private:
// Cookie manager for all tests
mojo::Remote<network::mojom::CookieManager> cookie_manager_;
};
TEST_F(PrefetchContainerTest, ConstructContainer) {
GURL test_url = GURL("https://www.test.com/");
PrefetchType test_type = PrefetchType(/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/true,
/*can_prefetch_subresources=*/false);
size_t test_prediction_index = 4;
PrefetchContainer prefetch_container(test_url, test_type,
test_prediction_index);
EXPECT_EQ(prefetch_container.GetUrl(), test_url);
EXPECT_EQ(prefetch_container.GetOriginalPredictionIndex(),
test_prediction_index);
EXPECT_EQ(prefetch_container.GetPrefetchType(), test_type);
EXPECT_FALSE(prefetch_container.IsDecoy());
prefetch_container.SetIsDecoy(true);
EXPECT_TRUE(prefetch_container.IsDecoy());
}
TEST_F(PrefetchContainerTest, PrefetchStatus) {
PrefetchContainer prefetch_container(
GURL("https://www.test.com/"),
PrefetchType(/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/true,
/*can_prefetch_subresources=*/false),
0);
EXPECT_FALSE(prefetch_container.HasPrefetchStatus());
prefetch_container.SetPrefetchStatus(
PrefetchProxyPrefetchStatus::kPrefetchUsedNoProbe);
EXPECT_TRUE(prefetch_container.HasPrefetchStatus());
EXPECT_EQ(prefetch_container.GetPrefetchStatus(),
PrefetchProxyPrefetchStatus::kPrefetchUsedNoProbe);
}
TEST_F(PrefetchContainerTest, CookieListener) {
GURL test_url = GURL("https://www.test.com/");
PrefetchContainer prefetch_container(
test_url,
PrefetchType(/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/true,
/*can_prefetch_subresources=*/false),
0);
EXPECT_FALSE(prefetch_container.HaveCookiesChanged());
base::RunLoop run_loop;
prefetch_container.RegisterCookieListener(
base::BindOnce(
[](base::RunLoop* run_loop, const GURL& expected_url,
const GURL& cookie_changed_url) {
if (expected_url != cookie_changed_url)
return;
run_loop->Quit();
},
&run_loop, test_url),
cookie_manager());
EXPECT_FALSE(prefetch_container.HaveCookiesChanged());
EXPECT_TRUE(SetCookie(test_url, "testing"));
run_loop.Run();
EXPECT_TRUE(prefetch_container.HaveCookiesChanged());
}
TEST_F(PrefetchContainerTest, HandlePrefetchedResponse) {
PrefetchContainer prefetch_container(
GURL("https://www.test.com/"),
PrefetchType(/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/true,
/*can_prefetch_subresources=*/false),
0);
EXPECT_FALSE(prefetch_container.HasPrefetchedResponse());
std::string body = "test_body";
std::unique_ptr<PrefetchedMainframeResponseContainer> prefetched_response =
std::make_unique<PrefetchedMainframeResponseContainer>(
net::IsolationInfo(), network::mojom::URLResponseHead::New(),
std::make_unique<std::string>(body));
prefetch_container.SetPrefetchedResponse(std::move(prefetched_response));
ASSERT_TRUE(prefetch_container.HasPrefetchedResponse());
std::unique_ptr<PrefetchedMainframeResponseContainer> cloned_response =
prefetch_container.ClonePrefetchedResponse();
ASSERT_TRUE(cloned_response);
EXPECT_EQ(*cloned_response->TakeBody(), body);
ASSERT_TRUE(prefetch_container.HasPrefetchedResponse());
std::unique_ptr<PrefetchedMainframeResponseContainer> taken_response =
prefetch_container.ReleasePrefetchedResponse();
ASSERT_TRUE(taken_response);
EXPECT_EQ(*taken_response->TakeBody(), body);
EXPECT_FALSE(prefetch_container.HasPrefetchedResponse());
}
TEST_F(PrefetchContainerTest, IsPrefetchedResponseValid) {
PrefetchContainer prefetch_container(
GURL("https://www.test.com/"),
PrefetchType(/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/true,
/*can_prefetch_subresources=*/false),
0);
EXPECT_FALSE(prefetch_container.HasPrefetchedResponse());
EXPECT_FALSE(
prefetch_container.IsPrefetchedResponseValid(base::TimeDelta::Max()));
std::unique_ptr<PrefetchedMainframeResponseContainer> prefetched_response =
std::make_unique<PrefetchedMainframeResponseContainer>(
net::IsolationInfo(), network::mojom::URLResponseHead::New(),
std::make_unique<std::string>(""));
prefetch_container.SetPrefetchedResponse(std::move(prefetched_response));
ASSERT_TRUE(prefetch_container.HasPrefetchedResponse());
EXPECT_TRUE(
prefetch_container.IsPrefetchedResponseValid(base::TimeDelta::Max()));
EXPECT_FALSE(prefetch_container.IsPrefetchedResponseValid(base::TimeDelta()));
}
TEST_F(PrefetchContainerTest, NoStatePrefetchStatus) {
PrefetchContainer prefetch_container(
GURL("https://www.test.com/"),
PrefetchType(/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/true,
/*can_prefetch_subresources=*/true),
0);
EXPECT_EQ(prefetch_container.GetNoStatePrefetchStatus(),
PrefetchContainer::NoStatePrefetchStatus::kNotStarted);
prefetch_container.SetNoStatePrefetchStatus(
PrefetchContainer::NoStatePrefetchStatus::kInProgress);
EXPECT_EQ(prefetch_container.GetNoStatePrefetchStatus(),
PrefetchContainer::NoStatePrefetchStatus::kInProgress);
prefetch_container.SetNoStatePrefetchStatus(
PrefetchContainer::NoStatePrefetchStatus::kSucceeded);
EXPECT_EQ(prefetch_container.GetNoStatePrefetchStatus(),
PrefetchContainer::NoStatePrefetchStatus::kSucceeded);
}
TEST_F(PrefetchContainerTest, ChangePrefetchType) {
GURL test_url = GURL("https://www.test.com/");
PrefetchType cross_origin_private =
PrefetchType(/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/true,
/*can_prefetch_subresources=*/false);
PrefetchType cross_origin_private_with_subresources = PrefetchType(
/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/true,
/*can_prefetch_subresources=*/true);
PrefetchType cross_origin_public =
PrefetchType(/*use_isolated_network_context=*/true,
/*use_prefetch_proxy=*/false,
/*can_prefetch_subresources=*/false);
PrefetchType same_origin_public = PrefetchType(
/*use_isolated_network_context=*/false,
/*use_prefetch_proxy=*/false,
/*can_prefetch_subresources=*/false);
PrefetchContainer prefetch_container(test_url, cross_origin_private, 0);
base::HistogramTester histogram_tester;
// Test invalid state changes.
prefetch_container.ChangePrefetchType(cross_origin_public);
EXPECT_EQ(prefetch_container.GetPrefetchType(), cross_origin_private);
histogram_tester.ExpectUniqueSample(
"PrefetchProxy.WasPrefetchTypeStateChangeValid", false, 1);
prefetch_container.ChangePrefetchType(same_origin_public);
EXPECT_EQ(prefetch_container.GetPrefetchType(), cross_origin_private);
histogram_tester.ExpectUniqueSample(
"PrefetchProxy.WasPrefetchTypeStateChangeValid", false, 2);
// Test valid state change.
prefetch_container.ChangePrefetchType(cross_origin_private_with_subresources);
EXPECT_EQ(prefetch_container.GetPrefetchType(),
cross_origin_private_with_subresources);
histogram_tester.ExpectTotalCount(
"PrefetchProxy.WasPrefetchTypeStateChangeValid", 3);
histogram_tester.ExpectBucketCount(
"PrefetchProxy.WasPrefetchTypeStateChangeValid", false, 2);
histogram_tester.ExpectBucketCount(
"PrefetchProxy.WasPrefetchTypeStateChangeValid", true, 1);
}
} // namespace