#include "device/fido/cable/fido_cable_discovery.h"
#include <algorithm>
#include <memory>
#include <string_view>
#include <utility>
#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_advertisement.h"
#include "device/bluetooth/test/bluetooth_test.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/cable/fido_ble_uuids.h"
#include "device/fido/cable/fido_cable_device.h"
#include "device/fido/cable/fido_cable_handshake_handler.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/mock_fido_discovery_observer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/test/scoped_feature_list.h"
#include "device/bluetooth/floss/floss_features.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/startup/browser_init_params.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "device/fido/mac/util.h"
#endif
_;
NiceMock;
Sequence;
namespace device {
namespace {
constexpr auto kTestCableVersion = …;
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
constexpr auto kTestCableVersionNumber = …;
#endif
constexpr CableEidArray kClientEid = …;
constexpr char kUuidFormattedClientEid[] = …;
constexpr CableEidArray kAuthenticatorEid = …;
constexpr CableEidArray kInvalidAuthenticatorEid = …;
constexpr CableSessionPreKeyArray kTestSessionPreKey = …;
#if !BUILDFLAG(IS_WIN)
constexpr CableEidArray kSecondaryClientEid = …;
constexpr char kUuidFormattedSecondaryClientEid[] = …;
constexpr CableEidArray kSecondaryAuthenticatorEid = …;
constexpr CableSessionPreKeyArray kSecondarySessionPreKey = …;
#endif
constexpr char kTestBleDeviceAddress[] = …;
constexpr char kTestBleDeviceName[] = …;
std::unique_ptr<MockBluetoothDevice> CreateTestBluetoothDevice() { … }
ACTION_P(ReturnFromAsyncCall, closure) { … }
MATCHER_P2(IsAdvertisementContent,
expected_client_eid,
expected_uuid_formatted_client_eid,
"") { … }
class CableMockBluetoothAdvertisement : public BluetoothAdvertisement { … };
class CableMockAdapter : public MockBluetoothAdapter { … };
class FakeHandshakeHandler : public FidoCableV1HandshakeHandler { … };
class FakeFidoCableDiscovery : public FidoCableDiscovery { … };
}
class FidoCableDiscoveryTest : public ::testing::Test { … };
TEST_F(FidoCableDiscoveryTest, TestDiscoveryFails) { … }
TEST_F(FidoCableDiscoveryTest, TestDiscoveryStartedWithUnpoweredAdapter) { … }
TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsNewDevice) { … }
TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsNewAppleDevice) { … }
#if BUILDFLAG(IS_MAC)
TEST_F(FidoCableDiscoveryTest, TestDiscoveryDoesNotUseBluetoothIfUnauthorized) {
fido::mac::ScopedProcessIsSignedOverride scoped_process_is_signed_override(
fido::mac::CodeSigningState::kSigned);
auto cable_discovery = CreateDiscovery();
NiceMock<MockFidoDiscoveryObserver> mock_observer;
EXPECT_CALL(mock_observer,
DiscoveryStarted(cable_discovery.get(), true,
std::vector<FidoAuthenticator*>()));
cable_discovery->set_observer(&mock_observer);
auto mock_adapter = CableMockAdapter::MakeWithUndeterminedPermission();
EXPECT_CALL(*mock_adapter, IsPowered()).Times(0);
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
task_environment_.FastForwardUntilNoTasksRemain();
}
TEST_F(FidoCableDiscoveryTest,
TestDiscoveryAssumesBluetoothAuthorizedIfUnsigned) {
fido::mac::ScopedProcessIsSignedOverride scoped_process_is_signed_override(
fido::mac::CodeSigningState::kNotSigned);
auto cable_discovery = CreateDiscovery();
NiceMock<MockFidoDiscoveryObserver> mock_observer;
EXPECT_CALL(mock_observer,
DiscoveryStarted(cable_discovery.get(), true,
std::vector<FidoAuthenticator*>()));
EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _));
cable_discovery->set_observer(&mock_observer);
auto mock_adapter = CableMockAdapter::MakeWithUndeterminedPermission();
EXPECT_CALL(*mock_adapter, IsPowered())
.WillRepeatedly(::testing::Return(true));
mock_adapter->ExpectDiscoveryWithScanCallback(kAuthenticatorEid);
mock_adapter->ExpectRegisterAdvertisementWithResponse(
true , kClientEid, kUuidFormattedClientEid);
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
task_environment_.FastForwardUntilNoTasksRemain();
}
#endif
TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsIncorrectDevice) { … }
#if !BUILDFLAG(IS_WIN)
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithMultipleEids) { … }
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithPartialAdvertisementSuccess) { … }
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithAdvertisementFailures) { … }
#endif
TEST_F(FidoCableDiscoveryTest, TestUnregisterAdvertisementUponDestruction) { … }
TEST_F(FidoCableDiscoveryTest, TestUnregisterAdvertisementUponStop) { … }
TEST_F(FidoCableDiscoveryTest, TestStopWithNoAdvertisementsSucceeds) { … }
TEST_F(FidoCableDiscoveryTest, TestResumeDiscoveryAfterPoweredOn) { … }
#if BUILDFLAG(IS_CHROMEOS)
TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsNewDeviceFloss) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(floss::features::kFlossEnabled);
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::BrowserInitParamsPtr init_params =
chromeos::BrowserInitParams::GetForTests()->Clone();
init_params->is_floss_available = true;
init_params->use_floss_bluetooth = true;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
#endif
auto cable_discovery = CreateDiscovery();
NiceMock<MockFidoDiscoveryObserver> mock_observer;
EXPECT_CALL(mock_observer,
DiscoveryStarted(cable_discovery.get(), true,
std::vector<FidoAuthenticator*>()));
EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _));
cable_discovery->set_observer(&mock_observer);
auto mock_adapter = CableMockAdapter::MakePoweredOn();
mock_adapter->ExpectLEScan(kAuthenticatorEid);
mock_adapter->ExpectRegisterAdvertisementWithResponse(
true , kClientEid, kUuidFormattedClientEid);
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
task_environment_.FastForwardUntilNoTasksRemain();
}
#endif
}