blob: ac927e84980ba99258ce77b9a2d213eba0ceb588 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/prefetch/aw_prefetch_manager.h"
#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_browser_context_store.h"
#include "android_webview/common/aw_features.h"
#include "base/android/jni_android.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/task_environment.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_content_client_initializer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace android_webview {
class AwPrefetchManagerTest : public testing::Test {
protected:
void SetUp() override {
test_content_client_initializer_ =
new content::TestContentClientInitializer();
browser_context_ = std::make_unique<content::TestBrowserContext>();
}
void TearDown() override {
// Drain the message queue before destroying
// |test_content_client_initializer_|, otherwise a posted task may call
// content::GetNetworkConnectionTracker() after
// TestContentClientInitializer's destructor sets it to null.
base::RunLoop().RunUntilIdle();
browser_context_.reset();
delete test_content_client_initializer_;
}
// Create the TestBrowserThreads.
content::BrowserTaskEnvironment task_environment_;
raw_ptr<content::TestContentClientInitializer>
test_content_client_initializer_;
std::unique_ptr<content::TestBrowserContext> browser_context_;
};
// Tests that setting the CacheConfig on the PrefetchManager applies it
// correctly.
TEST_F(AwPrefetchManagerTest, UpdateCacheConfig) {
AwPrefetchManager prefetch_manager(browser_context_.get());
prefetch_manager.SetTtlInSec(base::android::AttachCurrentThread(),
/*ttl_in_sec=*/60 * 10);
prefetch_manager.SetMaxPrefetches(base::android::AttachCurrentThread(),
/* max_prefetches=*/5);
EXPECT_EQ(prefetch_manager.GetTtlInSec(base::android::AttachCurrentThread()),
60 * 10);
EXPECT_EQ(
prefetch_manager.GetMaxPrefetches(base::android::AttachCurrentThread()),
5);
}
TEST_F(AwPrefetchManagerTest, MaxPrefetchReachesLimit) {
AwPrefetchManager prefetch_manager(browser_context_.get());
prefetch_manager.SetTtlInSec(base::android::AttachCurrentThread(),
/*ttl_in_sec=*/60 * 10);
prefetch_manager.SetMaxPrefetches(base::android::AttachCurrentThread(),
/* max_prefetches=*/3);
// Add more prefetch requests than the limit.
for (int i = 0; i < 5; ++i) {
prefetch_manager.StartPrefetchRequest(
base::android::AttachCurrentThread(),
"https://example.com/" + base::NumberToString(i),
/*prefetch_params=*/nullptr, /*callback=*/nullptr,
/*callback_executor=*/nullptr);
}
// Check the number of prefetches after exceeding the limit.
EXPECT_EQ(prefetch_manager.GetAllPrefetchKeysForTesting().size(), 3u);
// Add one more to trigger a removal
prefetch_manager.StartPrefetchRequest(
base::android::AttachCurrentThread(), "https://example.com/last",
/*prefetch_params=*/nullptr, /*callback=*/nullptr,
/*callback_executor=*/nullptr);
EXPECT_EQ(prefetch_manager.GetAllPrefetchKeysForTesting().size(),
3u); // Should still be at the limit
}
TEST_F(AwPrefetchManagerTest, RemoveOldestPrefetchHandle) {
AwPrefetchManager prefetch_manager(browser_context_.get());
prefetch_manager.SetTtlInSec(base::android::AttachCurrentThread(),
/*ttl_in_sec=*/60 * 10);
prefetch_manager.SetMaxPrefetches(base::android::AttachCurrentThread(),
/* max_prefetches=*/2);
// 1. Make two requests.
prefetch_manager.StartPrefetchRequest(
base::android::AttachCurrentThread(), "https://example.com/0",
/*prefetch_params=*/nullptr, /*callback=*/nullptr,
/*callback_executor=*/nullptr);
prefetch_manager.StartPrefetchRequest(
base::android::AttachCurrentThread(), "https://example.com/1",
/*prefetch_params=*/nullptr, /*callback=*/nullptr,
/*callback_executor=*/nullptr);
// 2. Capture the initial prefetches.
std::vector<int32_t> initial_prefetches =
prefetch_manager.GetAllPrefetchKeysForTesting();
EXPECT_EQ(initial_prefetches.size(), 2u);
// 3. Do the third request.
prefetch_manager.StartPrefetchRequest(
base::android::AttachCurrentThread(), "https://example.com/2",
/*prefetch_params=*/nullptr, /*callback=*/nullptr,
/*callback_executor=*/nullptr);
std::vector<int32_t> current_prefetches =
prefetch_manager.GetAllPrefetchKeysForTesting();
EXPECT_EQ(current_prefetches.size(), 2u);
// Verify that the oldest prefetch is removed.
auto it0 = std::find(current_prefetches.cbegin(), current_prefetches.cend(),
initial_prefetches.front());
EXPECT_EQ(it0, current_prefetches.cend());
// Last added element isn't included in the initials
auto it1 = std::find(initial_prefetches.cbegin(), initial_prefetches.cend(),
current_prefetches.back());
EXPECT_EQ(it1, initial_prefetches.cend());
EXPECT_EQ(current_prefetches.at(0), initial_prefetches.at(1));
}
TEST_F(AwPrefetchManagerTest, UpdateMaxPrefetchesIsRespected) {
AwPrefetchManager prefetch_manager(browser_context_.get());
prefetch_manager.SetTtlInSec(base::android::AttachCurrentThread(),
/*ttl_in_sec=*/60 * 10);
// set MaxPrefetches to a big number, 5.
prefetch_manager.SetMaxPrefetches(base::android::AttachCurrentThread(),
/* max_prefetches=*/5);
// Make five requests.
for (int i = 0; i < 5; ++i) {
prefetch_manager.StartPrefetchRequest(
base::android::AttachCurrentThread(),
"https://example.com/" + base::NumberToString(i),
/*prefetch_params=*/nullptr, /*callback=*/nullptr,
/*callback_executor=*/nullptr);
}
EXPECT_EQ(prefetch_manager.GetAllPrefetchKeysForTesting().size(), 5u);
// Now, let's lower that number with more than 1. Let's say 2.
prefetch_manager.SetMaxPrefetches(base::android::AttachCurrentThread(),
/* max_prefetches=*/2);
// Adding another request.
prefetch_manager.StartPrefetchRequest(
base::android::AttachCurrentThread(), "https://example.com/6",
/*prefetch_params=*/nullptr, /*callback=*/nullptr,
/*callback_executor=*/nullptr);
// Should be on the latest setting, 2.
EXPECT_EQ(prefetch_manager.GetAllPrefetchKeysForTesting().size(), 2u);
}
TEST_F(AwPrefetchManagerTest, PrefetchHandleKeysAlwaysIncrement) {
AwPrefetchManager prefetch_manager(browser_context_.get());
prefetch_manager.SetTtlInSec(base::android::AttachCurrentThread(),
/*ttl_in_sec=*/60 * 10);
prefetch_manager.SetMaxPrefetches(base::android::AttachCurrentThread(),
/* max_prefetches=*/5);
// Confirm the initial values.
int last_prefetch_key = prefetch_manager.GetLastPrefetchKeyForTesting();
EXPECT_EQ(last_prefetch_key, -1);
// Add more than the max allowed prefetches (triggering evictions) while
// ensuring that the prefetch handle keys always increment confirming that the
// prefetches are both sorted in the order they were added and that their keys
// are never reused.
for (int i = 0; i < 10; ++i) {
int prefetch_key = prefetch_manager.StartPrefetchRequest(
base::android::AttachCurrentThread(),
"https://example.com/" + base::NumberToString(i),
/*prefetch_params=*/nullptr, /*callback=*/nullptr,
/*callback_executor=*/nullptr);
EXPECT_EQ(prefetch_key, last_prefetch_key + 1);
last_prefetch_key = prefetch_key;
}
}
} // namespace android_webview