// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "chrome/browser/chromeos/extensions/printing_metrics/printing_metrics_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/policy_test_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "content/public/test/browser_test.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/printing/cups_print_job.h"
#include "chrome/browser/ash/printing/cups_print_job_manager_factory.h"
#include "chrome/browser/ash/printing/history/print_job_history_service_factory.h"
#include "chrome/browser/ash/printing/history/test_print_job_history_service_observer.h"
#include "chrome/browser/ash/printing/test_cups_print_job_manager.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "base/version.h"
#include "chromeos/crosapi/mojom/printing_metrics.mojom.h"
#include "chromeos/crosapi/mojom/test_controller.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "chromeos/lacros/lacros_test_helper.h"
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
namespace extensions {
namespace {
constexpr char kTitle[] = "title";
constexpr char kUpdateManifestPath[] =
"/extensions/api_test/printing_metrics/update_manifest.xml";
// The managed_storage extension has a key defined in its manifest, so that
// its extension ID is well-known and the policy system can push policies for
// the extension.
constexpr char kTestExtensionID[] = "cmgkkmeeoiceijkpmaabbmpgnkpaaela";
#if BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<KeyedService> BuildTestCupsPrintJobManager(
content::BrowserContext* context) {
return std::make_unique<ash::TestCupsPrintJobManager>(
Profile::FromBrowserContext(context));
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace
class PrintingMetricsApiTest : public ExtensionApiTest {
public:
PrintingMetricsApiTest() {}
PrintingMetricsApiTest(const PrintingMetricsApiTest&) = delete;
PrintingMetricsApiTest& operator=(const PrintingMetricsApiTest&) = delete;
~PrintingMetricsApiTest() override = default;
protected:
void SetUpInProcessBrowserTestFixture() override {
// Init the user policy provider.
policy_provider_.SetDefaultReturns(
/*is_initialization_complete_return=*/true,
/*is_first_policy_load_complete_return=*/true);
policy_provider_.SetAutoRefresh();
policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
&policy_provider_);
#if BUILDFLAG(IS_CHROMEOS_ASH)
create_services_subscription_ =
BrowserContextDependencyManager::GetInstance()
->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
&PrintingMetricsApiTest::OnWillCreateBrowserContextServices,
base::Unretained(this)));
#endif
ExtensionApiTest::SetUpInProcessBrowserTestFixture();
}
const Extension* extension() {
return ExtensionRegistry::Get(profile())->enabled_extensions().GetByID(
kTestExtensionID);
}
void ForceInstallExtensionByPolicy() {
policy_test_utils::SetUpEmbeddedTestServer(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
policy_test_utils::SetExtensionInstallForcelistPolicy(
kTestExtensionID, embedded_test_server()->GetURL(kUpdateManifestPath),
profile(), &policy_provider_);
ASSERT_TRUE(extension());
}
void CreateAndCancelPrintJob(const std::string& job_title) {
base::RunLoop run_loop;
#if BUILDFLAG(IS_CHROMEOS_ASH)
ash::TestPrintJobHistoryServiceObserver observer(
ash::PrintJobHistoryServiceFactory::GetForBrowserContext(
browser()->profile()),
run_loop.QuitClosure());
std::unique_ptr<ash::CupsPrintJob> print_job =
std::make_unique<ash::CupsPrintJob>(
chromeos::Printer(), /*job_id=*/0, job_title,
/*total_page_number=*/1,
::printing::PrintJob::Source::kPrintPreview,
/*source_id=*/"", ash::printing::proto::PrintSettings());
ash::TestCupsPrintJobManager* print_job_manager =
static_cast<ash::TestCupsPrintJobManager*>(
ash::CupsPrintJobManagerFactory::GetForBrowserContext(
browser()->profile()));
print_job_manager->CreatePrintJob(print_job.get());
print_job_manager->CancelPrintJob(print_job.get());
#else
GetTestController()->CreateAndCancelPrintJob(job_title,
run_loop.QuitClosure());
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
run_loop.Run();
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::TestController* GetTestController() {
auto* service = chromeos::LacrosService::Get();
if (!service->IsRegistered<crosapi::mojom::PrintingMetrics>() ||
!service->IsAvailable<crosapi::mojom::TestController>() ||
service->GetInterfaceVersion<crosapi::mojom::TestController>() <
static_cast<int>(crosapi::mojom::TestController::MethodMinVersions::
kCreateAndCancelPrintJobMinVersion)) {
LOG(ERROR) << "Unsupported ash version.";
return nullptr;
}
return service->GetRemote<crosapi::mojom::TestController>().get();
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_;
private:
#if BUILDFLAG(IS_CHROMEOS_ASH)
void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
ash::CupsPrintJobManagerFactory::GetInstance()->SetTestingFactory(
context, base::BindRepeating(&BuildTestCupsPrintJobManager));
}
base::CallbackListSubscription create_services_subscription_;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
};
IN_PROC_BROWSER_TEST_F(PrintingMetricsApiTest, GetPrintJobs) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
if (!GetTestController() ||
!chromeos::IsAshVersionAtLeastForTesting(base::Version({120, 0, 6079}))) {
GTEST_SKIP() << "Unsupported ash version.";
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
ForceInstallExtensionByPolicy();
CreateAndCancelPrintJob(kTitle);
Browser* const new_browser = CreateBrowser(profile());
SetCustomArg(kTitle);
extensions::ResultCatcher catcher;
ASSERT_TRUE(ui_test_utils::NavigateToURL(
new_browser, extension()->GetResourceURL("get_print_jobs.html")));
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
IN_PROC_BROWSER_TEST_F(PrintingMetricsApiTest, OnPrintJobFinished) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
if (!GetTestController()) {
GTEST_SKIP() << "Unsupported ash version.";
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
ForceInstallExtensionByPolicy();
ResultCatcher catcher;
Browser* const new_browser = CreateBrowser(profile());
ASSERT_TRUE(ui_test_utils::NavigateToURL(
new_browser, extension()->GetResourceURL("on_print_job_finished.html")));
CreateAndCancelPrintJob(kTitle);
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
// Ensure that extensions that are not pre-installed by policy throw an install
// warning if they request the printingMetrics permission in the manifest and
// that such extensions don't see the chrome.printingMetrics namespace.
IN_PROC_BROWSER_TEST_F(PrintingMetricsApiTest, IsRestrictedToPolicyExtension) {
ASSERT_TRUE(RunExtensionTest("printing_metrics",
{.extension_url = "api_not_available.html"},
{.ignore_manifest_warnings = true}));
base::FilePath extension_path =
test_data_dir_.AppendASCII("printing_metrics");
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile());
const extensions::Extension* extension =
GetExtensionByPath(registry->enabled_extensions(), extension_path);
EXPECT_THAT(
extension->install_warnings(),
testing::Contains(testing::Field(
&extensions::InstallWarning::message,
"'printingMetrics' is not allowed for specified install location.")));
}
} // namespace extensions