chromium/chrome/browser/ui/webui/print_preview/extension_printer_handler_adapter_ash_browsertest.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/print_preview/extension_printer_handler_adapter_ash.h"

#include <utility>

#include "base/path_service.h"
#include "base/test/repeating_test_future.h"
#include "base/test/test_future.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "chrome/browser/ash/crosapi/crosapi_ash.h"
#include "chrome/browser/ash/crosapi/crosapi_manager.h"
#include "chrome/browser/ash/crosapi/extension_printer_service_ash.h"
#include "chrome/browser/ash/crosapi/test_controller_ash.h"
#include "chrome/browser/ui/webui/print_preview/printer_handler.h"
#include "chrome/test/base/chromeos/ash_browser_test_starter.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chromeos/crosapi/mojom/test_controller.mojom-test-utils.h"
#include "chromeos/crosapi/mojom/test_controller.mojom.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace printing {

namespace {

class ExtensionPrinterHandlerAdapterAshBrowserTest
    : public InProcessBrowserTest {
 public:
  ExtensionPrinterHandlerAdapterAshBrowserTest() = default;
  ~ExtensionPrinterHandlerAdapterAshBrowserTest() override = default;

  void SetUpOnMainThread() override {
    InProcessBrowserTest::SetUpOnMainThread();

    if (!ash_starter_.HasLacrosArgument()) {
      GTEST_SKIP() << "This test needs to run together with Lacros but the "
                      "--lacros-chrome-path switch is missing.";
    }
    ash_starter_.StartLacros(this);

    // Wait until StandaloneBrowserTestController binds with
    // test_controller_ash_.
    CHECK(crosapi::TestControllerAsh::Get());
    base::test::TestFuture<void> waiter;
    crosapi::TestControllerAsh::Get()
        ->on_standalone_browser_test_controller_bound()
        .Post(FROM_HERE, waiter.GetCallback());
    EXPECT_TRUE(waiter.Wait());

    lacros_waiter_.emplace(crosapi::TestControllerAsh::Get()
                               ->GetStandaloneBrowserTestController());
    // Asks Lacros to use a fake extension printer handler to process printing
    // requests coming from ash.
    lacros_waiter_->SetFakeExtensionPrinterHandler();
  }

 protected:
  ExtensionPrinterHandlerAdapterAsh printer_handler_;

 private:
  void SetUpInProcessBrowserTestFixture() override {
    InProcessBrowserTest::SetUpInProcessBrowserTestFixture();

    if (!HasLacrosArgument()) {
      return;
    }

    ASSERT_TRUE(ash_starter_.PrepareEnvironmentForLacros());
  }

  bool HasLacrosArgument() const { return ash_starter_.HasLacrosArgument(); }

  test::AshBrowserTestStarter ash_starter_;
  std::optional<crosapi::TestControllerAsh> test_controller_ash_;
  std::optional<crosapi::mojom::StandaloneBrowserTestControllerAsyncWaiter>
      lacros_waiter_;
};

}  // namespace

// Verifies GetPrinters returns two fake lacros extension printers.
IN_PROC_BROWSER_TEST_F(ExtensionPrinterHandlerAdapterAshBrowserTest,
                       StartGetPrinters) {
  base::test::RepeatingTestFuture<base::Value::List> printers_added_future;
  base::test::TestFuture<void> done_future;

  printer_handler_.StartGetPrinters(printers_added_future.GetCallback(),
                                    done_future.GetCallback());
  const base::Value::List& printers = printers_added_future.Take();
  EXPECT_EQ(printers.size(), 2u);

  const base::Value::Dict& printer1 = printers[0].GetDict();
  base::ExpectDictStringValue("Test Printer 01", printer1, "name");
  base::ExpectDictStringValue("Test Printer Provider", printer1,
                              "extensionName");
  const base::Value::Dict& printer2 = printers[1].GetDict();
  base::ExpectDictStringValue("Test Printer 02", printer2, "name");
  base::ExpectDictStringValue("Test Printer Provider", printer2,
                              "extensionName");

  done_future.Get();
}

// Verifies GetCapability returns a capability supporting pdf content type.
IN_PROC_BROWSER_TEST_F(ExtensionPrinterHandlerAdapterAshBrowserTest,
                       GetCapability) {
  base::test::TestFuture<base::Value::Dict> capability_future;
  printer_handler_.StartGetCapability("fake-extension-id:Test Printer 01",
                                      capability_future.GetCallback());
  const base::Value::Dict& capability = capability_future.Get();

  base::ExpectDictStringValue("1.0", capability, "version");
  const base::Value::List* supportedContentTypes =
      capability.FindListByDottedPath("printer.supported_content_type");
  ASSERT_TRUE(supportedContentTypes);
  EXPECT_EQ(supportedContentTypes->size(), 1u);

  const base::Value& contentType1 = (*supportedContentTypes)[0];
  EXPECT_TRUE(contentType1.is_dict());
  base::ExpectDictStringValue("application/pdf", contentType1.GetDict(),
                              "content_type");
}

// Verifies StartPrint returns a success status.
IN_PROC_BROWSER_TEST_F(ExtensionPrinterHandlerAdapterAshBrowserTest,
                       StartPrint) {
  const std::u16string job_title = u"Test Print Job";
  base::Value::Dict settings = base::test::ParseJsonDict(R"(
    {
      "copies": 2,
      "color": "color"
    }
  )");
  scoped_refptr<base::RefCountedMemory> print_data =
      base::MakeRefCounted<base::RefCountedString>("Test print data");

  base::test::TestFuture<base::Value> print_future;
  printer_handler_.StartPrint(
      job_title, std::move(settings), print_data,
      base::BindOnce(
          [](base::OnceCallback<void(base::Value)> callback,
             const base::Value& error) {
            std::move(callback).Run(error.Clone());
          },
          print_future.GetCallback()));
  // A successful print job should return a none value.
  EXPECT_TRUE(print_future.Get().is_none());
}

// Verifies StartGrantPrinterAccess returns print info.
IN_PROC_BROWSER_TEST_F(ExtensionPrinterHandlerAdapterAshBrowserTest,
                       StartGrantPrinterAccess) {
  const std::string printer_id =
      "test_printer_id_123:fake_ext_id:fake_device_guid";

  base::test::TestFuture<base::Value::Dict> printer_info_future;
  printer_handler_.StartGrantPrinterAccess(
      printer_id, base::BindOnce(
                      [](base::OnceCallback<void(base::Value::Dict)> callback,
                         const base::Value::Dict& printer_info) {
                        std::move(callback).Run(printer_info.Clone());
                      },
                      printer_info_future.GetCallback()));

  const base::Value::Dict& actual_printer_info = printer_info_future.Get();
  base::ExpectDictStringValue(printer_id, actual_printer_info, "printerId");
  base::ExpectDictStringValue("Test Printer 01", actual_printer_info, "name");
}

}  // namespace printing