Commit b5ac8cdc authored by Ian Barkley-Yeung's avatar Ian Barkley-Yeung Committed by Chromium LUCI CQ

Test that non-WebUI pages do not report JS errors to Google

Test that the WebUI JavaScript error reporting system will not report
non-WebUI JavaScript errors even if they happen in the same tab.

Bug: chromium:1162353, chromium:1121816
Fixed: chromium:1162353
Change-Id: If44d5777b7c4bc955e8101d60cd6029036d6bd1e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2617529Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Commit-Queue: Ian Barkley-Yeung <iby@chromium.org>
Auto-Submit: Ian Barkley-Yeung <iby@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841747}
parent d02cd47a
......@@ -39,6 +39,7 @@ source_set("test_support") {
"//base/test:test_support",
"//build:chromeos_buildflags",
"//chrome/common:constants",
"//components/crash/content/browser/error_reporting",
"//components/crash/content/browser/error_reporting:mock_crash_endpoint",
]
}
......
......@@ -6,12 +6,22 @@
#include "base/check.h"
#include "base/logging.h"
#include "components/crash/content/browser/error_reporting/javascript_error_report.h"
#include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
MockChromeJsErrorReportProcessor::MockChromeJsErrorReportProcessor() = default;
MockChromeJsErrorReportProcessor::~MockChromeJsErrorReportProcessor() = default;
void MockChromeJsErrorReportProcessor::SendErrorReport(
JavaScriptErrorReport error_report,
base::OnceClosure completion_callback,
content::BrowserContext* browser_context) {
++send_count_;
ChromeJsErrorReportProcessor::SendErrorReport(
std::move(error_report), std::move(completion_callback), browser_context);
}
void MockChromeJsErrorReportProcessor::SetAsDefault() {
LOG(INFO) << "MockChromeJsErrorReportProcessor installed as error processor";
JsErrorReportProcessor::SetDefault(this);
......
......@@ -21,6 +21,13 @@ class MockChromeJsErrorReportProcessor : public ChromeJsErrorReportProcessor {
public:
MockChromeJsErrorReportProcessor();
// JsErrorReportProcessor:
void SendErrorReport(JavaScriptErrorReport error_report,
base::OnceClosure completion_callback,
content::BrowserContext* browser_context) override;
int send_count() const { return send_count_; }
// Controls what is returned from GetCrashEndpoint() override.
void SetCrashEndpoint(std::string crash_endpoint);
// Controls what is returned from GetCrashEndpointStaging() override.
......@@ -61,6 +68,8 @@ class MockChromeJsErrorReportProcessor : public ChromeJsErrorReportProcessor {
private:
~MockChromeJsErrorReportProcessor() override;
// Number of times SendErrorReport has been called.
int send_count_ = 0;
std::string crash_endpoint_;
std::string crash_endpoint_staging_;
#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
......
......@@ -4,6 +4,7 @@
#include <memory>
#include "base/containers/contains.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h"
......@@ -26,6 +27,8 @@
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/page_transition_types.h"
......@@ -41,6 +44,83 @@ namespace {
// escapes.
constexpr char kPageLoadMessage[] =
"WebUI%20JS%20Error%3A%20printing%20error%20on%20page%20load";
// A simple webpage that generates a JavaScript error on load.
constexpr char kJavaScriptErrorPage[] = R"(
<html>
<head>
<meta charset="utf-8">
<title>Bad Page</title>
</head>
<body>
Text
<script>
console.error('special error message for WebUIJSErrorReportingTest');
</script>
</body>
</html>
)";
// The error message printed by kJavaScriptErrorPage
constexpr char kWebpageErrorMessage[] =
"special error message for WebUIJSErrorReportingTest";
// Callback for the error_page_test_server_. Tells the server to always return
// the contents of kJavaScriptErrorPage.
std::unique_ptr<net::test_server::HttpResponse> ReturnErrorPage(
const net::test_server::HttpRequest&) {
auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
http_response->set_content(kJavaScriptErrorPage);
http_response->set_content_type("text/html");
return http_response;
}
// A class that waits for a log message like
// [4193947:4193947:0108/114152.942981:INFO:CONSOLE(10)] "special error message
// for WebUIJSErrorReportingTest", source: http://127.0.0.1:36521/index.html
// (10)
// to appear and then calls a callback (usually a RunLoop quit closure)
class ScopedLogMessageWatcher {
public:
explicit ScopedLogMessageWatcher(base::RepeatingClosure callback)
: callback_(std::move(callback)) {
previous_handler_ = logging::GetLogMessageHandler();
// base::LogMessageHandlerFunction must be a pure function, not a functor,
// so we need a global to find this object again.
CHECK(current_handler_ == nullptr);
current_handler_ = this;
logging::SetLogMessageHandler(&ScopedLogMessageWatcher::MessageHandler);
}
ScopedLogMessageWatcher(const ScopedLogMessageWatcher&) = delete;
ScopedLogMessageWatcher& operator=(const ScopedLogMessageWatcher&) = delete;
~ScopedLogMessageWatcher() {
CHECK(current_handler_ == this);
current_handler_ = nullptr;
logging::SetLogMessageHandler(previous_handler_);
}
private:
static bool MessageHandler(int severity,
const char* file,
int line,
size_t message_start,
const std::string& str) {
CHECK(current_handler_ != nullptr);
if (base::Contains(str, kWebpageErrorMessage)) {
current_handler_->callback_.Run();
}
if (current_handler_->previous_handler_ != nullptr) {
return (*current_handler_->previous_handler_)(severity, file, line,
message_start, str);
}
return false;
}
static ScopedLogMessageWatcher* current_handler_;
base::RepeatingClosure callback_;
logging::LogMessageHandlerFunction previous_handler_;
};
ScopedLogMessageWatcher* ScopedLogMessageWatcher::current_handler_ = nullptr;
} // namespace
class WebUIJSErrorReportingTest : public InProcessBrowserTest {
......@@ -49,6 +129,14 @@ class WebUIJSErrorReportingTest : public InProcessBrowserTest {
CHECK(error_url_.is_valid());
}
void SetUpOnMainThread() override {
error_page_test_server_.RegisterRequestHandler(
base::BindRepeating(&ReturnErrorPage));
EXPECT_TRUE(error_page_test_server_.Start());
InProcessBrowserTest::SetUpOnMainThread();
}
void SetUpInProcessBrowserTestFixture() override {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
features::kSendWebUIJavaScriptErrorReports,
......@@ -58,6 +146,10 @@ class WebUIJSErrorReportingTest : public InProcessBrowserTest {
}
protected:
// NoErrorsAfterNavigation needs a second embedded test server to serve up
// its error page, since embedded_test_server() is in use by the
// MockCrashEndpoint.
net::test_server::EmbeddedTestServer error_page_test_server_;
base::test::ScopedFeatureList scoped_feature_list_;
const GURL error_url_;
};
......@@ -171,3 +263,41 @@ IN_PROC_BROWSER_TEST_F(WebUIJSErrorReportingTest,
EXPECT_EQ(endpoint.report_count(), 2);
EXPECT_THAT(report.query, HasSubstr(kPageLoadMessage));
}
// Show that navigating from a WebUI page to a http page that produces
// JavaScript errors on load does not create an error report.
IN_PROC_BROWSER_TEST_F(WebUIJSErrorReportingTest, NoErrorsAfterNavigation) {
MockCrashEndpoint endpoint(embedded_test_server());
ScopedMockChromeJsErrorReportProcessor mock_processor(endpoint);
NavigateParams navigate(browser(), error_url_, ui::PAGE_TRANSITION_TYPED);
ui_test_utils::NavigateToURL(&navigate);
// Wait for page load error report.
MockCrashEndpoint::Report report = endpoint.WaitForReport();
EXPECT_EQ(endpoint.report_count(), 1);
EXPECT_EQ(mock_processor.processor().send_count(), 1);
{
base::RunLoop run_loop;
ScopedLogMessageWatcher log_watcher(run_loop.QuitClosure());
NavigateParams navigate_to_http(
browser(), error_page_test_server_.GetURL("/index.html"),
ui::PAGE_TRANSITION_TYPED);
ui_test_utils::NavigateToURL(&navigate_to_http);
run_loop.Run(); // Run until the error message is seen on the console.
}
// Now run more to make sure the error reporter system doesn't have an
// in-flight error report.
{
base::RunLoop run_loop2;
run_loop2.RunUntilIdle();
}
// Count should not change.
EXPECT_EQ(endpoint.report_count(), 1);
EXPECT_EQ(mock_processor.processor().send_count(), 1);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment