blob: 88bcc815c4109df9ed44715dd5d1fdb830f8f43a [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "base/functional/callback_helpers.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/browser/web_applications/test/web_app_test_utils.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_install_params.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/webapps/browser/install_result_code.h"
#include "content/public/test/browser_test.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace web_app {
namespace {
constexpr char kBadIconErrorTemplate[] = R"({
"!url": "$1banners/manifest_test_page.html",
"background_installation": false,
"install_surface": 15,
"stages": [ {
"!stage": "OnIconsRetrieved",
"icons_downloaded_result": "Completed",
"icons_http_results": [ {
"http_code_desc": "Not Found",
"http_status_code": 404,
"icon_url": "$1banners/bad_icon.png"
} ],
"is_generated_icon": true
} ]
}
)";
// Drops all CR and LF characters.
std::string TrimLineEndings(base::StringPiece text) {
return base::CollapseWhitespaceASCII(
text,
/*trim_sequences_with_line_breaks=*/true);
}
} // namespace
class WebAppInternalsBrowserTest : public WebAppControllerBrowserTest {
public:
WebAppInternalsBrowserTest() = default;
WebAppInternalsBrowserTest(const WebAppInternalsBrowserTest&) = delete;
WebAppInternalsBrowserTest& operator=(const WebAppInternalsBrowserTest&) =
delete;
~WebAppInternalsBrowserTest() override = default;
void SetUp() override {
embedded_test_server()->AddDefaultHandlers(GetChromeTestDataDir());
embedded_test_server()->RegisterRequestHandler(
base::BindRepeating(&WebAppInternalsBrowserTest::RequestHandlerOverride,
base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
WebAppControllerBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
test::WaitUntilReady(WebAppProvider::GetForTest(browser()->profile()));
WebAppControllerBrowserTest::SetUpOnMainThread();
}
AppId InstallWebApp(const GURL& app_url) {
EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), app_url));
AppId app_id;
base::RunLoop run_loop;
GetProvider().scheduler().FetchManifestAndInstall(
webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON,
browser()->tab_strip_model()->GetActiveWebContents()->GetWeakPtr(),
/*bypass_service_worker_check=*/false,
base::BindOnce(test::TestAcceptDialogCallback),
base::BindLambdaForTesting(
[&](const AppId& new_app_id, webapps::InstallResultCode code) {
EXPECT_EQ(code, webapps::InstallResultCode::kSuccessNewInstall);
app_id = new_app_id;
run_loop.Quit();
}),
/*use_fallback=*/true);
run_loop.Run();
return app_id;
}
WebAppProvider& GetProvider() {
return *WebAppProvider::GetForTest(browser()->profile());
}
std::unique_ptr<net::test_server::HttpResponse> RequestHandlerOverride(
const net::test_server::HttpRequest& request) {
if (request_override_)
return request_override_.Run(request);
return nullptr;
}
void OverrideHttpRequest(GURL url, net::HttpStatusCode http_status_code) {
request_override_ = base::BindLambdaForTesting(
[url = std::move(url),
http_status_code](const net::test_server::HttpRequest& request)
-> std::unique_ptr<net::test_server::HttpResponse> {
if (request.GetURL() != url)
return nullptr;
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(http_status_code);
return std::move(http_response);
});
}
private:
net::EmbeddedTestServer::HandleRequestCallback request_override_;
base::test::ScopedFeatureList scoped_feature_list_{
features::kRecordWebAppDebugInfo};
};
IN_PROC_BROWSER_TEST_F(WebAppInternalsBrowserTest,
PRE_InstallManagerErrorsPersist) {
OverrideHttpRequest(embedded_test_server()->GetURL("/banners/bad_icon.png"),
net::HTTP_NOT_FOUND);
AppId app_id = InstallWebApp(embedded_test_server()->GetURL(
"/banners/manifest_test_page.html?manifest=manifest_bad_icon.json"));
const WebApp* web_app = GetProvider().registrar_unsafe().GetAppById(app_id);
ASSERT_TRUE(web_app);
EXPECT_TRUE(web_app->is_generated_icon());
const std::string expected_error = base::ReplaceStringPlaceholders(
kBadIconErrorTemplate, {embedded_test_server()->base_url().spec()},
nullptr);
ASSERT_TRUE(GetProvider().install_manager().error_log());
ASSERT_EQ(1u, GetProvider().install_manager().error_log()->size());
const base::Value& error_log =
(*GetProvider().install_manager().error_log())[0];
EXPECT_TRUE(error_log.is_dict());
EXPECT_EQ(4u, error_log.GetDict().size());
EXPECT_EQ(TrimLineEndings(expected_error),
TrimLineEndings(error_log.DebugString()));
}
IN_PROC_BROWSER_TEST_F(WebAppInternalsBrowserTest,
InstallManagerErrorsPersist) {
test::WaitUntilReady(WebAppProvider::GetForTest(browser()->profile()));
ASSERT_TRUE(GetProvider().install_manager().error_log());
ASSERT_EQ(1u, GetProvider().install_manager().error_log()->size());
const base::Value& error_log =
(*GetProvider().install_manager().error_log())[0];
EXPECT_TRUE(error_log.is_dict());
EXPECT_EQ(4u, error_log.GetDict().size());
// Parses base url from the log: the port for embedded_test_server() changes
// on every test run.
const std::string* url_value = error_log.GetDict().FindString("!url");
ASSERT_TRUE(url_value);
GURL url{*url_value};
ASSERT_TRUE(url.is_valid());
const std::string expected_error = base::ReplaceStringPlaceholders(
kBadIconErrorTemplate, {url.GetWithEmptyPath().spec()}, nullptr);
EXPECT_EQ(TrimLineEndings(expected_error),
TrimLineEndings(error_log.DebugString()));
}
} // namespace web_app