blob: ad191a68485e724eebbcc5dcedd5849dd5216b8c [file] [log] [blame]
// Copyright 2022 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/strings/stringprintf.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/values_test_util.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/profiles/profile.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/api/usb/usb_api.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
#include "services/device/public/cpp/test/fake_usb_device_info.h"
#include "services/device/public/cpp/test/fake_usb_device_manager.h"
#include "services/device/public/cpp/test/mock_usb_mojo_device.h"
#include "services/device/public/mojom/usb_device.mojom.h"
namespace extensions {
namespace {
using ::base::test::RunOnceCallback;
using ::testing::_;
constexpr char kManifest[] =
R"(
{
"name": "ChromeUsbApiTest App",
"version": "1.0",
"manifest_version": 2,
"app": {
"background": {
"scripts": ["background_script.js"]
}
},
"permissions": ["usb"]
}
)";
// Need to fill it with an extension's url.
constexpr char kPolicySetting[] = R"(
[
{
"devices": [{ "vendor_id": 0, "product_id": 0 }],
"urls": ["%s"]
}
])";
class ChromeUsbApiTest : public ExtensionBrowserTest {
public:
void SetUpOnMainThread() override {
ExtensionBrowserTest::SetUpOnMainThread();
// Set fake USB device manager for extensions::UsbDeviceManager.
mojo::PendingRemote<device::mojom::UsbDeviceManager> usb_manager;
fake_usb_manager_.AddReceiver(usb_manager.InitWithNewPipeAndPassReceiver());
UsbDeviceManager::Get(profile())->SetDeviceManagerForTesting(
std::move(usb_manager));
base::RunLoop().RunUntilIdle();
}
protected:
void AddFakeDevice() {
std::vector<device::mojom::UsbConfigurationInfoPtr> configs;
configs.push_back(
device::FakeUsbDeviceInfo::CreateConfiguration(0xff, 0x00, 0x00, 1));
configs.push_back(
device::FakeUsbDeviceInfo::CreateConfiguration(0xff, 0x00, 0x00, 2));
fake_device_ = base::MakeRefCounted<device::FakeUsbDeviceInfo>(
0, 0, "Test Manufacturer", "Test Device", "ABC123", std::move(configs));
fake_usb_manager_.AddDevice(fake_device_);
fake_usb_manager_.SetMockForDevice(fake_device_->guid(), &mock_device_);
base::RunLoop().RunUntilIdle();
}
void SetUpPolicy(const Extension* extension) {
profile()->GetPrefs()->Set(
prefs::kManagedWebUsbAllowDevicesForUrls,
base::test::ParseJson(base::StringPrintf(
kPolicySetting, extension->url().spec().c_str())));
}
// `mock_device_`, `fake_device_`, and `fake_usb_manager_` must be declared in
// this order to avoid dangling pointers.
device::MockUsbMojoDevice mock_device_;
scoped_refptr<device::FakeUsbDeviceInfo> fake_device_;
device::FakeUsbDeviceManager fake_usb_manager_;
};
IN_PROC_BROWSER_TEST_F(ChromeUsbApiTest, GetDevicesByPolicy) {
extensions::TestExtensionDir dir;
dir.WriteManifest(kManifest);
dir.WriteFile(FILE_PATH_LITERAL("background_script.js"), R"(
chrome.test.sendMessage("ready", async () => {
chrome.usb.getDevices({
vendorId: 0,
productId: 0
}, function(devices) {
chrome.test.assertEq(1, devices.length);
const device = devices[0];
chrome.test.assertEq(0, device.vendorId);
chrome.test.assertEq(0, device.productId);
chrome.test.assertEq(0x0100, device.version);
chrome.test.assertEq("Test Device", device.productName);
chrome.test.assertEq("Test Manufacturer", device.manufacturerName);
chrome.test.assertEq("ABC123", device.serialNumber);
chrome.test.notifyPass();
});
});
)");
// Launch the test app.
ExtensionTestMessageListener ready_listener("ready",
ReplyBehavior::kWillReply);
extensions::ResultCatcher result_catcher;
const Extension* extension = LoadExtension(dir.UnpackedPath());
// Run the test.
SetUpPolicy(extension);
AddFakeDevice();
EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
ready_listener.Reply("ok");
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
IN_PROC_BROWSER_TEST_F(ChromeUsbApiTest, GetDevicesByPolicyNoPolicySet) {
extensions::TestExtensionDir dir;
dir.WriteManifest(kManifest);
dir.WriteFile(FILE_PATH_LITERAL("background_script.js"), R"(
chrome.test.sendMessage("ready", async () => {
chrome.usb.getDevices({
vendorId: 0,
productId: 0
}, function(devices) {
chrome.test.assertEq(0, devices.length);
chrome.test.notifyPass();
});
});
)");
// Launch the test app.
ExtensionTestMessageListener ready_listener("ready",
ReplyBehavior::kWillReply);
extensions::ResultCatcher result_catcher;
LoadExtension(dir.UnpackedPath());
// Run the test.
AddFakeDevice();
EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
ready_listener.Reply("ok");
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
IN_PROC_BROWSER_TEST_F(ChromeUsbApiTest, FindDevicesByPolicy) {
extensions::TestExtensionDir dir;
dir.WriteManifest(kManifest);
dir.WriteFile(FILE_PATH_LITERAL("background_script.js"), R"(
chrome.test.sendMessage("ready", async () => {
chrome.usb.findDevices({
vendorId: 0,
productId: 0
}, function(devices) {
chrome.test.assertEq(1, devices.length);
const device = devices[0];
chrome.test.assertEq(0, device.vendorId);
chrome.test.assertEq(0, device.productId);
chrome.test.notifyPass();
});
});
)");
// Launch the test app.
ExtensionTestMessageListener ready_listener("ready",
ReplyBehavior::kWillReply);
extensions::ResultCatcher result_catcher;
const Extension* extension = LoadExtension(dir.UnpackedPath());
EXPECT_CALL(mock_device_, Open)
.WillOnce(
RunOnceCallback<0>(device::mojom::UsbOpenDeviceResult::NewSuccess(
device::mojom::UsbOpenDeviceSuccess::OK)));
// Run the test.
SetUpPolicy(extension);
AddFakeDevice();
EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
ready_listener.Reply("ok");
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
IN_PROC_BROWSER_TEST_F(ChromeUsbApiTest, FindDevicesByPolicyNoPolicySet) {
extensions::TestExtensionDir dir;
dir.WriteManifest(kManifest);
dir.WriteFile(FILE_PATH_LITERAL("background_script.js"), R"(
chrome.test.sendMessage("ready", async () => {
chrome.usb.findDevices({
vendorId: 0,
productId: 0
}, function(devices) {
chrome.test.assertEq(undefined, devices);
chrome.test.notifyPass();
});
});
)");
// Launch the test app.
ExtensionTestMessageListener ready_listener("ready",
ReplyBehavior::kWillReply);
extensions::ResultCatcher result_catcher;
LoadExtension(dir.UnpackedPath());
// Run the test.
AddFakeDevice();
EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
ready_listener.Reply("ok");
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
IN_PROC_BROWSER_TEST_F(ChromeUsbApiTest, OnDevicesAdded) {
extensions::TestExtensionDir dir;
dir.WriteManifest(kManifest);
dir.WriteFile(FILE_PATH_LITERAL("background_script.js"), R"(
chrome.usb.onDeviceAdded.addListener(function(device) {
chrome.test.assertEq(0, device.vendorId);
chrome.test.assertEq(0, device.productId);
chrome.test.assertEq(0x0100, device.version);
chrome.test.assertEq("Test Device", device.productName);
chrome.test.assertEq("Test Manufacturer", device.manufacturerName);
chrome.test.assertEq("ABC123", device.serialNumber);
chrome.test.notifyPass();
});
)");
// Launch the test app.
extensions::ResultCatcher result_catcher;
const Extension* extension = LoadExtension(dir.UnpackedPath());
// Run the test.
SetUpPolicy(extension);
AddFakeDevice();
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
} // namespace
} // namespace extensions