0

extensions: Add WebAccessibleResourcesBrowserTest to desktop Android

This tests the web_accessible_resources extension manifest key.
Several tests are ported, but others are blocked on parts of the
extension system we haven't ported yet.

Bug: 390687767

Change-Id: I92414c3c9cb38cb88f642e049c40bd276a92ed51
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6182531
Reviewed-by: David Bertoni <dbertoni@chromium.org>
Commit-Queue: James Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1408236}
This commit is contained in:
James Cook
2025-01-17 16:25:41 -08:00
committed by Chromium LUCI CQ
parent 6684f8b3c8
commit 5415b48c64
6 changed files with 57 additions and 32 deletions

@ -36,6 +36,9 @@ PlatformTestExtensionLoader::~PlatformTestExtensionLoader() = default;
scoped_refptr<const Extension> PlatformTestExtensionLoader::LoadExtension(
const base::FilePath& path) {
// Clean up the kMetadataFolder if necessary.
file_util::MaybeCleanupMetadataFolder(path);
scoped_refptr<const Extension> extension = LoadExtensionFromDirectory(path);
if (!extension) {
return nullptr;

@ -64,19 +64,6 @@ const char kImportMinVersionNewer[] =
const char kImportMissing[] = "'import' extension is not installed.";
const char kImportNotSharedModule[] = "'import' is not a shared module.";
// Deletes files reserved for use by the Extension system in the kMetadataFolder
// and the kMetadataFolder itself if it is empty.
void MaybeCleanupMetadataFolder(const base::FilePath& extension_path) {
const std::vector<base::FilePath> reserved_filepaths =
file_util::GetReservedMetadataFilePaths(extension_path);
for (const auto& file : reserved_filepaths)
base::DeletePathRecursively(file);
const base::FilePath& metadata_dir = extension_path.Append(kMetadataFolder);
if (base::IsDirectoryEmpty(metadata_dir))
base::DeletePathRecursively(metadata_dir);
}
} // namespace
// static
@ -261,7 +248,7 @@ bool UnpackedInstaller::LoadExtension(mojom::ManifestLocation location,
// Clean up the kMetadataFolder if necessary. This prevents spurious
// warnings/errors and ensures we don't treat a user provided file as one by
// the Extension system.
MaybeCleanupMetadataFolder(extension_path_);
file_util::MaybeCleanupMetadataFolder(extension_path_);
// Treat presence of illegal filenames as a hard error for unpacked
// extensions. Don't do so for command line extensions since this breaks

@ -6,11 +6,10 @@
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/extension_platform_browsertest.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/version_info/channel.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
@ -18,12 +17,19 @@
#include "content/public/test/test_navigation_observer.h"
#include "extensions/browser/background_script_executor.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_features.h"
#include "extensions/common/features/feature_channel.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/test_extension_dir.h"
#include "net/dns/mock_host_resolver.h"
#include "testing/gmock/include/gmock/gmock.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/ui_test_utils.h"
#endif
namespace extensions {
namespace {
static constexpr char kManifestStub[] = R"({
@ -73,7 +79,7 @@ static constexpr char kFetchResourceScriptTemplate[] = R"(
)";
// Exercise web accessible resources with experimental extension features.
class WebAccessibleResourcesBrowserTest : public ExtensionBrowserTest {
class WebAccessibleResourcesBrowserTest : public ExtensionPlatformBrowserTest {
public:
explicit WebAccessibleResourcesBrowserTest(bool enable_feature = true) {
feature_list_.InitWithFeatureState(
@ -81,7 +87,7 @@ class WebAccessibleResourcesBrowserTest : public ExtensionBrowserTest {
}
void SetUpOnMainThread() override {
ExtensionBrowserTest::SetUpOnMainThread();
ExtensionPlatformBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
EXPECT_TRUE(embedded_test_server()->Start());
}
@ -114,8 +120,8 @@ IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesBrowserTest,
// Navigate to a test page and get the web contents.
base::FilePath test_page;
GURL gurl = embedded_test_server()->GetURL("example.com", "/simple.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
auto* web_contents = GetActiveWebContents();
ASSERT_TRUE(content::NavigateToURL(web_contents, gurl));
std::string script =
base::StringPrintf(kFetchResourceScriptTemplate,
@ -128,8 +134,11 @@ IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesBrowserTest,
ASSERT_TRUE(content::EvalJs(web_contents, script).ExtractBool());
}
#if !BUILDFLAG(IS_ANDROID)
// Exercise these resources being used in iframes in a web page. The navigation
// flow goes through a different path than resource fetching.
// TODO(crbug.com/390687767): Port to desktop Android. Fails due to a navigation
// to about:blank#blocked.
IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesBrowserTest,
UseDynamicUrlInIframe) {
// Load an extension that has one web accessible resource.
@ -194,6 +203,8 @@ IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesBrowserTest,
// Tests that navigating a main frame via location.href works if and only if
// the target resource is accessible to the main frame.
// Regression test for https://crbug.com/374503948.
// TODO(crbug.com/390687767): Port to desktop Android. Fails due to a navigation
// to about:blank#blocked.
IN_PROC_BROWSER_TEST_F(
WebAccessibleResourcesBrowserTest,
MainFrameLocationHrefUpdatesAreSubjectToAccessibleResources) {
@ -285,6 +296,7 @@ IN_PROC_BROWSER_TEST_F(
}
}
}
#endif // !BUILDFLAG(IS_ANDROID)
// A test suite that will run both with and without the dynamic URL feature
// enabled.
@ -300,9 +312,12 @@ INSTANTIATE_TEST_SUITE_P(All,
ParameterizedWebAccessibleResourcesBrowserTest,
testing::Bool());
#if !BUILDFLAG(IS_ANDROID)
// DNR, WAR, and use_dynamic_url with the extension feature. DNR does not
// currently succeed when redirecting to a resource using use_dynamic_url with
// query parameters.
// TODO(crbug.com/390687767): Port to desktop Android once chrome.runtime is
// fully ported. Right now the ExtensionTestMessageListener times out.
IN_PROC_BROWSER_TEST_P(ParameterizedWebAccessibleResourcesBrowserTest,
DeclarativeNetRequest) {
ExtensionTestMessageListener listener("ready");
@ -352,6 +367,7 @@ IN_PROC_BROWSER_TEST_P(ParameterizedWebAccessibleResourcesBrowserTest,
EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
}
}
#endif // !BUILDFLAG(IS_ANDROID)
// If `use_dynamic_url` is set to true in manifest.json, then the associated web
// accessible resource(s) can only be loaded using the dynamic url if using the
@ -369,8 +385,8 @@ IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesNonGuidBrowserTest,
// Navigate to a test page and get the web contents.
base::FilePath test_page;
GURL gurl = embedded_test_server()->GetURL("example.com", "/simple.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
auto* web_contents = GetActiveWebContents();
ASSERT_TRUE(content::NavigateToURL(web_contents, gurl));
std::string script =
base::StringPrintf(kFetchResourceScriptTemplate,
@ -397,11 +413,10 @@ IN_PROC_BROWSER_TEST_P(ParameterizedWebAccessibleResourcesBrowserTest,
ASSERT_TRUE(listener.WaitUntilSatisfied());
// Navigate to a non extension page.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContents* web_contents = GetActiveWebContents();
GURL gurl = embedded_test_server()->GetURL("example.com", "/empty.html");
content::TestNavigationObserver navigation_observer(web_contents);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
ASSERT_TRUE(content::NavigateToURL(web_contents, gurl));
ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
EXPECT_EQ(gurl, web_contents->GetLastCommittedURL());
EXPECT_EQ(net::Error::OK, navigation_observer.last_net_error_code());
@ -419,12 +434,11 @@ IN_PROC_BROWSER_TEST_P(ParameterizedWebAccessibleResourcesBrowserTest,
ASSERT_TRUE(listener.WaitUntilSatisfied());
// Navigate to a non extension page.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContents* web_contents = GetActiveWebContents();
GURL gurl = embedded_test_server()->GetURL(
"example.com", "/extensions/api_test/webrequest/script/index.html");
content::TestNavigationObserver navigation_observer(web_contents);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
ASSERT_TRUE(content::NavigateToURL(web_contents, gurl));
ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
EXPECT_EQ(gurl, web_contents->GetLastCommittedURL());
EXPECT_EQ(net::Error::OK, navigation_observer.last_net_error_code());
@ -439,12 +453,11 @@ IN_PROC_BROWSER_TEST_P(ParameterizedWebAccessibleResourcesBrowserTest,
ASSERT_TRUE(extension);
// Navigate to a non extension page.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContents* web_contents = GetActiveWebContents();
GURL gurl =
embedded_test_server()->GetURL("example.com", "/simple_with_script.html");
content::TestNavigationObserver navigation_observer(web_contents);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
ASSERT_TRUE(content::NavigateToURL(web_contents, gurl));
ASSERT_TRUE(navigation_observer.last_navigation_succeeded());
EXPECT_EQ(gurl, web_contents->GetLastCommittedURL());
EXPECT_EQ(net::Error::OK, navigation_observer.last_net_error_code());
@ -452,6 +465,9 @@ IN_PROC_BROWSER_TEST_P(ParameterizedWebAccessibleResourcesBrowserTest,
EXPECT_EQ("dnr redirect success", result.ExtractString());
}
#if !BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/390687767): Port to desktop Android. Currently the redirect
// doesn't happen.
class WebAccessibleResourcesBrowserRedirectTest
: public WebAccessibleResourcesBrowserTest {
protected:
@ -520,6 +536,7 @@ IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesBrowserRedirectTest, MV3) {
})",
"Extensions.WAR.XOriginWebAccessible.MV3");
}
#endif // !BUILDFLAG(IS_ANDROID)
} // namespace
} // namespace extensions

@ -1808,6 +1808,7 @@ if (is_android) {
"../browser/extensions/system_cpu_apitest.cc",
"../browser/extensions/system_memory_apitest.cc",
"../browser/extensions/test_resources_browsertest.cc",
"../browser/extensions/web_accessible_resources_browsertest.cc",
]
deps += [

@ -601,4 +601,17 @@ std::vector<base::FilePath> GetReservedMetadataFilePaths(
extension_path.Append(GetIndexedRulesetDirectoryRelativePath())};
}
void MaybeCleanupMetadataFolder(const base::FilePath& extension_path) {
const std::vector<base::FilePath> reserved_filepaths =
GetReservedMetadataFilePaths(extension_path);
for (const auto& file : reserved_filepaths) {
base::DeletePathRecursively(file);
}
const base::FilePath& metadata_dir = extension_path.Append(kMetadataFolder);
if (base::IsDirectoryEmpty(metadata_dir)) {
base::DeletePathRecursively(metadata_dir);
}
}
} // namespace extensions::file_util

@ -177,6 +177,10 @@ base::FilePath GetIndexedRulesetRelativePath(int static_ruleset_id);
std::vector<base::FilePath> GetReservedMetadataFilePaths(
const base::FilePath& extension_path);
// Deletes files reserved for use by the Extension system in the kMetadataFolder
// and the kMetadataFolder itself if it is empty.
void MaybeCleanupMetadataFolder(const base::FilePath& extension_path);
} // namespace file_util
} // namespace extensions