blob: 97a26db425af44423b2aa12940291a02f30386e6 [file] [log] [blame]
// Copyright 2022 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 "base/command_line.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/optimization_guide/browser_test_util.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/mojo_web_ui_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_logger.h"
#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.h"
#include "components/optimization_guide/optimization_guide_internals/webui/url_constants.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_controller_factory.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
namespace {
// TODO(crbug.com/1295080): Remove the test helpers that disable CSP once there
// is better support for disabling CSP in webui browser tests.
void SetUpWebUIDataSource(content::WebUI* web_ui,
const char* web_ui_host,
base::span<const webui::ResourcePath> resources,
int default_resource) {
auto source = base::WrapUnique(content::WebUIDataSource::Create(web_ui_host));
webui::SetupWebUIDataSource(source.get(), resources, default_resource);
// Disable CSP for tests so that EvalJS can be invoked without CSP violations.
source->DisableContentSecurityPolicy();
content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
source.release());
}
class TestWebUIControllerFactory : public content::WebUIControllerFactory {
public:
TestWebUIControllerFactory() = default;
std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
content::WebUI* web_ui,
const GURL& url) override {
if (url.host_piece() ==
optimization_guide_internals::kChromeUIOptimizationGuideInternalsHost) {
Profile* profile = Profile::FromWebUI(web_ui);
return std::make_unique<OptimizationGuideInternalsUI>(
web_ui,
OptimizationGuideKeyedServiceFactory::GetForProfile(profile)
->GetOptimizationGuideLogger(),
base::BindOnce(&SetUpWebUIDataSource, web_ui,
optimization_guide_internals::
kChromeUIOptimizationGuideInternalsHost));
}
return nullptr;
}
content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
const GURL& url) override {
if (url.host_piece() ==
optimization_guide_internals::kChromeUIOptimizationGuideInternalsHost)
return optimization_guide_internals::
kChromeUIOptimizationGuideInternalsHost;
return content::WebUI::kNoWebUI;
}
bool UseWebUIForURL(content::BrowserContext* browser_context,
const GURL& url) override {
return GetWebUIType(browser_context, url) != content::WebUI::kNoWebUI;
}
};
} // namespace
class OptimizationGuideInternalsPageBrowserTest : public MojoWebUIBrowserTest {
public:
OptimizationGuideInternalsPageBrowserTest() {
factory_ = std::make_unique<TestWebUIControllerFactory>();
content::WebUIControllerFactory::RegisterFactory(factory_.get());
feature_list_.InitWithFeatures(
{optimization_guide::features::kOptimizationHints}, {});
}
~OptimizationGuideInternalsPageBrowserTest() override = default;
void NavigateToInternalsPage() {
EXPECT_TRUE(ui_test_utils::NavigateToURL(
browser(), GURL(content::GetWebUIURLString(
optimization_guide_internals::
kChromeUIOptimizationGuideInternalsHost))));
}
protected:
std::unique_ptr<TestWebUIControllerFactory> factory_;
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(OptimizationGuideInternalsPageBrowserTest,
DebugLogEnabledOnInternalsPage) {
auto* logger =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->GetOptimizationGuideLogger();
EXPECT_FALSE(logger->ShouldEnableDebugLogs());
NavigateToInternalsPage();
// Once the internals page is open, debug logs should get enabled.
EXPECT_TRUE(logger->ShouldEnableDebugLogs());
}
IN_PROC_BROWSER_TEST_F(OptimizationGuideInternalsPageBrowserTest,
DebugLogEnabledOnCommandLineSwitch) {
auto* logger =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->GetOptimizationGuideLogger();
EXPECT_FALSE(logger->ShouldEnableDebugLogs());
base::CommandLine::ForCurrentProcess()->AppendSwitch(
optimization_guide::switches::kDebugLoggingEnabled);
// With the command-line switch, debug logs should get enabled.
EXPECT_TRUE(logger->ShouldEnableDebugLogs());
}
// Verifies log message is added when internals page is open.
IN_PROC_BROWSER_TEST_F(OptimizationGuideInternalsPageBrowserTest,
InternalsPageOpen) {
auto* logger =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->GetOptimizationGuideLogger();
EXPECT_FALSE(logger->ShouldEnableDebugLogs());
base::CommandLine::ForCurrentProcess()->AppendSwitch(
optimization_guide::switches::kDebugLoggingEnabled);
EXPECT_TRUE(logger->ShouldEnableDebugLogs());
NavigateToInternalsPage();
content::WebContents* internals_page_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
auto* service =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
service->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
chrome::AddTabAt(browser(), GURL(url::kAboutBlankURL), -1, true);
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("https://foo")));
service->CanApplyOptimization(GURL("https://foo"),
optimization_guide::proto::NOSCRIPT,
/*optimization_metadata=*/nullptr);
// Verify that log messages are added to the UI.
EXPECT_EQ(true, EvalJs(internals_page_web_contents, R"(
new Promise(resolve => {
setTimeout(() => {
const container = document.getElementById('log-message-container');
if (container.children[0].childElementCount > 2)
resolve(true);
}, 500);
});)"));
}