blob: 282db85aa6565c00674a2746ffd7f1c3536aaf4f [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <functional>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/json/json_writer.h"
#include "base/memory/ref_counted_memory.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/repeating_test_future.h"
#include "base/test/test_future.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/api/printer_provider/printer_provider_api.h"
#include "extensions/browser/api/printer_provider/printer_provider_api_factory.h"
#include "extensions/browser/api/printer_provider/printer_provider_print_job.h"
#include "extensions/browser/api/usb/usb_device_manager.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_id.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#include "services/device/public/cpp/test/fake_usb_device_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
namespace {
using ContextType = extensions::browser_test_util::ContextType;
using GetPrintersRepeatingFuture =
base::test::RepeatingTestFuture<base::Value::List, bool>;
base::Value::List FetchPrintersFromFuture(
std::unique_ptr<GetPrintersRepeatingFuture> future) {
base::Value::List printers_out;
while (true) {
auto [printers, done] = future->Take();
for (auto& printer : printers) {
EXPECT_TRUE(printer.is_dict());
printers_out.Append(std::move(printer));
}
if (done) {
break;
}
}
return printers_out;
}
std::pair<bool, std::string> ParsePrintResult(const base::Value& status) {
bool success = status.is_none();
std::string status_str = success ? "OK" : status.GetString();
return {success, status_str};
}
std::optional<std::string> SerializeDict(const base::Value::Dict& value) {
return base::WriteJson(value);
}
// Tests for chrome.printerProvider API.
class PrinterProviderApiTest : public ExtensionApiTest,
public testing::WithParamInterface<ContextType> {
public:
enum PrintRequestDataType {
PRINT_REQUEST_DATA_TYPE_NOT_SET,
PRINT_REQUEST_DATA_TYPE_BYTES
};
PrinterProviderApiTest() : ExtensionApiTest(GetParam()) {}
~PrinterProviderApiTest() override = default;
PrinterProviderApiTest(const PrinterProviderApiTest&) = delete;
PrinterProviderApiTest& operator=(const PrinterProviderApiTest&) = delete;
protected:
void StartGetPrintersRequest(
const PrinterProviderAPI::GetPrintersCallback& callback) {
PrinterProviderAPIFactory::GetInstance()
->GetForBrowserContext(profile())
->DispatchGetPrintersRequested(callback);
}
void StartPrintRequestWithNoData(const ExtensionId& extension_id,
PrinterProviderAPI::PrintCallback callback) {
PrinterProviderPrintJob job;
job.printer_id = extension_id + ":printer_id";
job.content_type = "application/pdf";
PrinterProviderAPIFactory::GetInstance()
->GetForBrowserContext(profile())
->DispatchPrintRequested(std::move(job), std::move(callback));
}
void StartPrintRequestUsingDocumentBytes(
const ExtensionId& extension_id,
PrinterProviderAPI::PrintCallback callback) {
PrinterProviderPrintJob job;
job.printer_id = extension_id + ":printer_id";
job.job_title = u"Print job";
job.content_type = "application/pdf";
const unsigned char kDocumentBytes[] = {'b', 'y', 't', 'e', 's'};
job.document_bytes = new base::RefCountedBytes(kDocumentBytes);
PrinterProviderAPIFactory::GetInstance()
->GetForBrowserContext(profile())
->DispatchPrintRequested(std::move(job), std::move(callback));
}
void StartCapabilityRequest(
const ExtensionId& extension_id,
PrinterProviderAPI::GetCapabilityCallback callback) {
PrinterProviderAPIFactory::GetInstance()
->GetForBrowserContext(profile())
->DispatchGetCapabilityRequested(extension_id + ":printer_id",
std::move(callback));
}
// Loads chrome.printerProvider test extension and initializes it for test.
// |test_param|.
// When the extension's background page is loaded, it will send a 'loaded'
// message. As a response to the message it will expect a string message
// specifying the test that should be run. When the extension initializes its
// state (e.g. registers listener for a chrome.printerProvider event) it will
// send the message 'ready', at which point the test may be started.
// If the extension is successfully initialized, |*extension_id_out| will be
// set to the loaded extension's id, otherwise it will remain unchanged.
void InitializePrinterProviderTestExtension(const std::string& extension_path,
const std::string& test_param,
ExtensionId* extension_id_out) {
ExtensionTestMessageListener loaded_listener("loaded",
ReplyBehavior::kWillReply);
ExtensionTestMessageListener ready_listener("ready");
const Extension* extension =
LoadExtension(test_data_dir_.AppendASCII(extension_path));
ASSERT_TRUE(extension);
ASSERT_TRUE(loaded_listener.WaitUntilSatisfied());
loaded_listener.Reply(test_param);
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
*extension_id_out = extension->id();
}
// Runs a test for chrome.printerProvider.onPrintRequested event.
// |test_param|: The test that should be run.
// |expected_result|: The print result the extension is expected to report.
void RunPrintRequestTestExtension(const std::string& test_param,
PrintRequestDataType data_type,
const std::string& expected_result) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_print",
test_param, &extension_id);
if (extension_id.empty())
return;
base::RunLoop run_loop;
bool success;
std::string status;
// TestFuture cannot be used with <const base::Value&>.
auto callback = base::BindLambdaForTesting([&](const base::Value& result) {
std::tie(success, status) = ParsePrintResult(result);
}).Then(run_loop.QuitClosure());
switch (data_type) {
case PRINT_REQUEST_DATA_TYPE_NOT_SET:
StartPrintRequestWithNoData(extension_id, std::move(callback));
break;
case PRINT_REQUEST_DATA_TYPE_BYTES:
StartPrintRequestUsingDocumentBytes(extension_id, std::move(callback));
break;
}
if (data_type != PRINT_REQUEST_DATA_TYPE_NOT_SET)
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
run_loop.Run();
EXPECT_EQ(expected_result, status);
EXPECT_EQ(expected_result == "OK", success);
}
// Runs a test for chrome.printerProvider.onGetCapabilityRequested
// event.
// |test_param|: The test that should be run.
// |expected_result|: The capability the extension is expected to report.
void RunPrinterCapabilitiesRequestTest(const std::string& test_param,
const std::string& expected_result) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension(
"printer_provider/request_capability", test_param, &extension_id);
if (extension_id.empty())
return;
base::test::TestFuture<base::Value::Dict> capability_future;
StartCapabilityRequest(extension_id, capability_future.GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
auto result = SerializeDict(capability_future.Get());
ASSERT_TRUE(result);
EXPECT_EQ(expected_result, *result);
}
bool SimulateExtensionUnload(const ExtensionId& extension_id) {
ExtensionRegistry* extension_registry = ExtensionRegistry::Get(profile());
scoped_refptr<const Extension> extension =
extension_registry->enabled_extensions().GetByID(extension_id);
if (!extension)
return false;
extension_registry->RemoveEnabled(extension_id);
extension_registry->TriggerOnUnloaded(extension.get(),
UnloadedExtensionReason::TERMINATE);
return true;
}
// Validates that set of printers reported by test extensions via
// chrome.printerProvider.onGetPritersRequested is the same as the set of
// printers in |expected_printers|. |expected_printers| contains list of
// printer objects formatted as a JSON string. It is assumed that the values
// in |expected_printers| are unique.
void ValidatePrinterListValue(
const base::Value::List& printers,
const std::vector<base::Value::Dict>& expected_printers) {
ASSERT_EQ(expected_printers.size(), printers.size());
for (const auto& printer_value : expected_printers) {
EXPECT_TRUE(base::Contains(printers, printer_value))
<< "Unable to find " << printer_value << " in " << printers;
}
}
};
INSTANTIATE_TEST_SUITE_P(EventPage,
PrinterProviderApiTest,
::testing::Values(ContextType::kEventPage));
INSTANTIATE_TEST_SUITE_P(ServiceWorker,
PrinterProviderApiTest,
::testing::Values(ContextType::kServiceWorker));
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, PrintJobSuccess) {
RunPrintRequestTestExtension("OK", PRINT_REQUEST_DATA_TYPE_BYTES, "OK");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, PrintJobAsyncSuccess) {
RunPrintRequestTestExtension("ASYNC_RESPONSE", PRINT_REQUEST_DATA_TYPE_BYTES,
"OK");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, PrintJobFailed) {
RunPrintRequestTestExtension("INVALID_TICKET", PRINT_REQUEST_DATA_TYPE_BYTES,
"INVALID_TICKET");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, NoPrintEventListener) {
RunPrintRequestTestExtension("NO_LISTENER", PRINT_REQUEST_DATA_TYPE_BYTES,
"FAILED");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest,
PrintRequestInvalidCallbackParam) {
RunPrintRequestTestExtension("INVALID_VALUE", PRINT_REQUEST_DATA_TYPE_BYTES,
"FAILED");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, PrintRequestDataNotSet) {
RunPrintRequestTestExtension("IGNORE_CALLBACK",
PRINT_REQUEST_DATA_TYPE_NOT_SET, "FAILED");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, PrintRequestExtensionUnloaded) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_print",
"IGNORE_CALLBACK", &extension_id);
ASSERT_FALSE(extension_id.empty());
base::RunLoop run_loop;
bool success;
std::string status;
// TestFuture cannot be used with <const base::Value&>.
StartPrintRequestUsingDocumentBytes(
extension_id, base::BindLambdaForTesting([&](const base::Value& result) {
std::tie(success, status) = ParsePrintResult(result);
}).Then(run_loop.QuitClosure()));
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
ASSERT_TRUE(SimulateExtensionUnload(extension_id));
run_loop.Run();
EXPECT_FALSE(success);
EXPECT_EQ("FAILED", status);
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetCapabilitySuccess) {
RunPrinterCapabilitiesRequestTest("OK", "{\"capability\":\"value\"}");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetCapabilityAsyncSuccess) {
RunPrinterCapabilitiesRequestTest("ASYNC_RESPONSE",
"{\"capability\":\"value\"}");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, EmptyCapability) {
RunPrinterCapabilitiesRequestTest("EMPTY", "{}");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, NoCapabilityEventListener) {
RunPrinterCapabilitiesRequestTest("NO_LISTENER", "{}");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, CapabilityInvalidValue) {
RunPrinterCapabilitiesRequestTest("INVALID_VALUE", "{}");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetCapabilityExtensionUnloaded) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_capability",
"IGNORE_CALLBACK", &extension_id);
ASSERT_FALSE(extension_id.empty());
base::test::TestFuture<base::Value::Dict> capability_future;
StartCapabilityRequest(extension_id, capability_future.GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
ASSERT_TRUE(SimulateExtensionUnload(extension_id));
auto result = SerializeDict(capability_future.Get());
ASSERT_TRUE(result);
EXPECT_EQ("{}", *result);
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetPrintersSuccess) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"OK", &extension_id);
ASSERT_FALSE(extension_id.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
std::vector<base::Value::Dict> expected_printers;
expected_printers.push_back(
base::Value::Dict()
.Set("description", "Test printer")
.Set("extensionId", extension_id)
.Set("extensionName", "Test printer provider")
.Set("id", base::StringPrintf("%s:printer1", extension_id.c_str()))
.Set("name", "Printer 1"));
expected_printers.push_back(
base::Value::Dict()
.Set("extensionId", extension_id)
.Set("extensionName", "Test printer provider")
.Set("id",
base::StringPrintf("%s:printerNoDesc", extension_id.c_str()))
.Set("name", "Printer 2"));
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
ValidatePrinterListValue(printers, expected_printers);
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetPrintersAsyncSuccess) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"ASYNC_RESPONSE", &extension_id);
ASSERT_FALSE(extension_id.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
std::vector<base::Value::Dict> expected_printers;
expected_printers.push_back(
base::Value::Dict()
.Set("description", "Test printer")
.Set("extensionId", extension_id)
.Set("extensionName", "Test printer provider")
.Set("id", base::StringPrintf("%s:printer1", extension_id.c_str()))
.Set("name", "Printer 1"));
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
ValidatePrinterListValue(printers, expected_printers);
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetPrintersTwoExtensions) {
ResultCatcher catcher;
ExtensionId extension_id_1;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"OK", &extension_id_1);
ASSERT_FALSE(extension_id_1.empty());
ExtensionId extension_id_2;
InitializePrinterProviderTestExtension(
"printer_provider/request_printers_second", "OK", &extension_id_2);
ASSERT_FALSE(extension_id_2.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
std::vector<base::Value::Dict> expected_printers;
expected_printers.push_back(
base::Value::Dict()
.Set("description", "Test printer")
.Set("extensionId", extension_id_1)
.Set("extensionName", "Test printer provider")
.Set("id", base::StringPrintf("%s:printer1", extension_id_1.c_str()))
.Set("name", "Printer 1"));
expected_printers.push_back(
base::Value::Dict()
.Set("extensionId", extension_id_1)
.Set("extensionName", "Test printer provider")
.Set("id",
base::StringPrintf("%s:printerNoDesc", extension_id_1.c_str()))
.Set("name", "Printer 2"));
expected_printers.push_back(
base::Value::Dict()
.Set("description", "Test printer")
.Set("extensionId", extension_id_2)
.Set("extensionName", "Test printer provider")
.Set("id", base::StringPrintf("%s:printer1", extension_id_2.c_str()))
.Set("name", "Printer 1"));
expected_printers.push_back(
base::Value::Dict()
.Set("extensionId", extension_id_2)
.Set("extensionName", "Test printer provider")
.Set("id",
base::StringPrintf("%s:printerNoDesc", extension_id_2.c_str()))
.Set("name", "Printer 2"));
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
ValidatePrinterListValue(printers, expected_printers);
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest,
GetPrintersTwoExtensionsBothUnloaded) {
ResultCatcher catcher;
ExtensionId extension_id_1;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"IGNORE_CALLBACK", &extension_id_1);
ASSERT_FALSE(extension_id_1.empty());
ExtensionId extension_id_2;
InitializePrinterProviderTestExtension(
"printer_provider/request_printers_second", "IGNORE_CALLBACK",
&extension_id_2);
ASSERT_FALSE(extension_id_2.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
ASSERT_TRUE(SimulateExtensionUnload(extension_id_1));
ASSERT_TRUE(SimulateExtensionUnload(extension_id_2));
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
EXPECT_TRUE(printers.empty());
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest,
GetPrintersTwoExtensionsOneFails) {
ResultCatcher catcher;
ExtensionId extension_id_1;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"NOT_ARRAY", &extension_id_1);
ASSERT_FALSE(extension_id_1.empty());
ExtensionId extension_id_2;
InitializePrinterProviderTestExtension(
"printer_provider/request_printers_second", "OK", &extension_id_2);
ASSERT_FALSE(extension_id_2.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
std::vector<base::Value::Dict> expected_printers;
expected_printers.push_back(
base::Value::Dict()
.Set("description", "Test printer")
.Set("extensionId", extension_id_2)
.Set("extensionName", "Test printer provider")
.Set("id", base::StringPrintf("%s:printer1", extension_id_2.c_str()))
.Set("name", "Printer 1"));
expected_printers.push_back(
base::Value::Dict()
.Set("extensionId", extension_id_2)
.Set("extensionName", "Test printer provider")
.Set("id",
base::StringPrintf("%s:printerNoDesc", extension_id_2.c_str()))
.Set("name", "Printer 2"));
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
ValidatePrinterListValue(printers, expected_printers);
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest,
GetPrintersTwoExtensionsOneWithNoListener) {
ResultCatcher catcher;
ExtensionId extension_id_1;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"NO_LISTENER", &extension_id_1);
ASSERT_FALSE(extension_id_1.empty());
ExtensionId extension_id_2;
InitializePrinterProviderTestExtension(
"printer_provider/request_printers_second", "OK", &extension_id_2);
ASSERT_FALSE(extension_id_2.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
std::vector<base::Value::Dict> expected_printers;
expected_printers.push_back(
base::Value::Dict()
.Set("description", "Test printer")
.Set("extensionId", extension_id_2)
.Set("extensionName", "Test printer provider")
.Set("id", base::StringPrintf("%s:printer1", extension_id_2.c_str()))
.Set("name", "Printer 1"));
expected_printers.push_back(
base::Value::Dict()
.Set("extensionId", extension_id_2)
.Set("extensionName", "Test printer provider")
.Set("id",
base::StringPrintf("%s:printerNoDesc", extension_id_2.c_str()))
.Set("name", "Printer 2"));
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
ValidatePrinterListValue(printers, expected_printers);
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetPrintersNoListener) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"NO_LISTENER", &extension_id);
ASSERT_FALSE(extension_id.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
EXPECT_TRUE(printers.empty());
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetPrintersNotArray) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"NOT_ARRAY", &extension_id);
ASSERT_FALSE(extension_id.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
EXPECT_TRUE(printers.empty());
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest,
GetPrintersInvalidPrinterValueType) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"INVALID_PRINTER_TYPE", &extension_id);
ASSERT_FALSE(extension_id.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
EXPECT_TRUE(printers.empty());
}
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetPrintersInvalidPrinterValue) {
ResultCatcher catcher;
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"INVALID_PRINTER", &extension_id);
ASSERT_FALSE(extension_id.empty());
auto get_printers_repeating_future =
std::make_unique<GetPrintersRepeatingFuture>();
StartGetPrintersRequest(get_printers_repeating_future->GetCallback());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
auto printers =
FetchPrintersFromFuture(std::move(get_printers_repeating_future));
EXPECT_TRUE(printers.empty());
}
// These tests are separate out from the main test class because the USB api
// is only available to apps.
class PrinterProviderUsbApiTest : public PrinterProviderApiTest {
public:
PrinterProviderUsbApiTest() = default;
PrinterProviderUsbApiTest(const PrinterProviderUsbApiTest&) = delete;
PrinterProviderUsbApiTest& operator=(const PrinterProviderUsbApiTest&) =
delete;
protected:
void StartGetUsbPrinterInfoRequest(
const ExtensionId& extension_id,
const device::mojom::UsbDeviceInfo& device,
PrinterProviderAPI::GetPrinterInfoCallback callback) {
PrinterProviderAPIFactory::GetInstance()
->GetForBrowserContext(profile())
->DispatchGetUsbPrinterInfoRequested(extension_id, device,
std::move(callback));
}
// Run a test for the chrome.printerProvider.onGetUsbPrinterInfoRequested
// event.
// |test_param|: The test that should be run.
// |expected_result|: The printer info that the app is expected to report.
void RunUsbPrinterInfoRequestTest(const std::string& test_param) {
ResultCatcher catcher;
device::mojom::UsbDeviceInfoPtr device =
usb_manager_.CreateAndAddDevice(0, 0, "Google", "USB Printer", "");
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/usb_printers",
test_param, &extension_id);
ASSERT_FALSE(extension_id.empty());
base::test::TestFuture<base::Value::Dict> future;
StartGetUsbPrinterInfoRequest(extension_id, *device, future.GetCallback());
ASSERT_TRUE(future.Get().empty());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
device::FakeUsbDeviceManager usb_manager_;
};
// These are only instantiated for event page-based packaged apps.
INSTANTIATE_TEST_SUITE_P(EventPage,
PrinterProviderUsbApiTest,
::testing::Values(ContextType::kEventPage));
IN_PROC_BROWSER_TEST_P(PrinterProviderUsbApiTest, GetUsbPrinterInfo) {
ResultCatcher catcher;
device::mojom::UsbDeviceInfoPtr device =
usb_manager_.CreateAndAddDevice(0, 0, "Google", "USB Printer", "");
ExtensionId extension_id;
InitializePrinterProviderTestExtension("printer_provider/usb_printers", "OK",
&extension_id);
ASSERT_FALSE(extension_id.empty());
UsbDeviceManager* device_manager = UsbDeviceManager::Get(profile());
base::Value::Dict expected_printer_info =
base::Value::Dict()
.Set("description", "This printer is a USB device.")
.Set("extensionId", extension_id)
.Set("extensionName", "Test USB printer provider")
.Set("id",
base::StringPrintf("%s:usbDevice-%u", extension_id.c_str(),
device_manager->GetIdFromGuid(device->guid)))
.Set("name", "Test Printer");
base::test::TestFuture<base::Value::Dict> future;
StartGetUsbPrinterInfoRequest(extension_id, *device, future.GetCallback());
ASSERT_EQ(future.Get(), expected_printer_info);
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
IN_PROC_BROWSER_TEST_P(PrinterProviderUsbApiTest,
GetUsbPrinterInfoEmptyResponse) {
RunUsbPrinterInfoRequestTest("EMPTY_RESPONSE");
}
IN_PROC_BROWSER_TEST_P(PrinterProviderUsbApiTest, GetUsbPrinterInfoNoListener) {
RunUsbPrinterInfoRequestTest("NO_LISTENER");
}
} // namespace
} // namespace extensions