Commit 66353c23 authored by Balazs Engedy's avatar Balazs Engedy Committed by Commit Bot

Apply Occam's razor to U2fDiscovery.

No production code is calling U2fDiscovery::Stop, and all observer
method implementations are no-ops.

Similarly, no U2fDiscovery has more than a single observer added, and
the only time that observer is removed is when both the discovery and
that observer (the owner) dies.

It sounds like we are not going to make use of this functionality in the
near future, so this CL removes:
 -- the ability to Stop() U2fDiscoveries, and
 -- the ability to have more than a single Observer per U2fDiscovery.

The CL also moves slightly more functionality into the U2fDiscovery base
class from derived classes, most importantly with the goal of making
sure the fake and production implementations function consistently in
the following areas:
 -- U2fDiscovery now keeps track of whether Start NotifyDiscoveryStarted
    have been called, and exposes corresponding getters.
 -- It is now enforced that Start() and NotifyDiscoveryStarted() can
    be called once each, and in this order, as well as that
    NotifyDeviceAdded cannot be called before Start() is called.
 -- It is now enforced that Observer::DiscoveryStarted is never invoked
    synchronously while Start() is still on the call stack.

Bug: 822244, 823686
Change-Id: Ia029646d43481a1a2ca58452577727f96d6aade1
Reviewed-on: https://chromium-review.googlesource.com/964301
Commit-Queue: Balazs Engedy <engedy@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#544379}
parent 178757f0
...@@ -6,7 +6,11 @@ ...@@ -6,7 +6,11 @@
#include <utility> #include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace device { namespace device {
...@@ -15,69 +19,32 @@ namespace test { ...@@ -15,69 +19,32 @@ namespace test {
// FakeFidoDiscovery ---------------------------------------------------------- // FakeFidoDiscovery ----------------------------------------------------------
FakeFidoDiscovery::FakeFidoDiscovery(U2fTransportProtocol transport, FakeFidoDiscovery::FakeFidoDiscovery(U2fTransportProtocol transport,
StartStopMode mode) StartMode mode)
: transport_(transport), : FidoDiscovery(transport), mode_(mode) {}
mode_(mode),
start_called_callback_(wait_for_start_loop_.QuitClosure()),
stop_called_callback_(wait_for_stop_loop_.QuitClosure()) {}
FakeFidoDiscovery::~FakeFidoDiscovery() = default; FakeFidoDiscovery::~FakeFidoDiscovery() = default;
void FakeFidoDiscovery::WaitForCallToStart() { void FakeFidoDiscovery::WaitForCallToStart() {
wait_for_start_loop_.Run(); wait_for_start_loop_.Run();
ASSERT_FALSE(start_called_callback_);
}
void FakeFidoDiscovery::WaitForCallToStop() {
wait_for_stop_loop_.Run();
ASSERT_FALSE(stop_called_callback_);
} }
void FakeFidoDiscovery::SimulateStarted(bool success) { void FakeFidoDiscovery::SimulateStarted(bool success) {
ASSERT_FALSE(is_running_); ASSERT_FALSE(is_running());
is_running_ = success;
NotifyDiscoveryStarted(success); NotifyDiscoveryStarted(success);
} }
void FakeFidoDiscovery::SimulateStopped(bool success) {
ASSERT_TRUE(is_running_);
is_running_ = !success;
NotifyDiscoveryStopped(success);
}
void FakeFidoDiscovery::WaitForCallToStartAndSimulateSuccess() { void FakeFidoDiscovery::WaitForCallToStartAndSimulateSuccess() {
WaitForCallToStart(); WaitForCallToStart();
SimulateStarted(true /* success */); SimulateStarted(true /* success */);
} }
void FakeFidoDiscovery::WaitForCallToStopAndSimulateSuccess() { void FakeFidoDiscovery::StartInternal() {
WaitForCallToStop(); wait_for_start_loop_.Quit();
SimulateStopped(true /* success */);
}
U2fTransportProtocol FakeFidoDiscovery::GetTransportProtocol() const {
return transport_;
}
void FakeFidoDiscovery::Start() {
if (is_running_)
return;
ASSERT_TRUE(start_called_callback_) << "Start called twice."; if (mode_ == StartMode::kAutomatic) {
std::move(start_called_callback_).Run(); base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&FakeFidoDiscovery::SimulateStarted,
if (mode_ == StartStopMode::kAutomatic) base::Unretained(this), true /* success */));
SimulateStarted(true /* success */); }
}
void FakeFidoDiscovery::Stop() {
if (!is_running_)
return;
ASSERT_TRUE(stop_called_callback_) << "Stop called twice.";
std::move(stop_called_callback_).Run();
if (mode_ == StartStopMode::kAutomatic)
SimulateStopped(true /* success */);
} }
// ScopedFakeFidoDiscoveryFactory --------------------------------------------- // ScopedFakeFidoDiscoveryFactory ---------------------------------------------
...@@ -86,14 +53,14 @@ ScopedFakeFidoDiscoveryFactory::ScopedFakeFidoDiscoveryFactory() = default; ...@@ -86,14 +53,14 @@ ScopedFakeFidoDiscoveryFactory::ScopedFakeFidoDiscoveryFactory() = default;
ScopedFakeFidoDiscoveryFactory::~ScopedFakeFidoDiscoveryFactory() = default; ScopedFakeFidoDiscoveryFactory::~ScopedFakeFidoDiscoveryFactory() = default;
FakeFidoDiscovery* ScopedFakeFidoDiscoveryFactory::ForgeNextHidDiscovery( FakeFidoDiscovery* ScopedFakeFidoDiscoveryFactory::ForgeNextHidDiscovery(
FakeFidoDiscovery::StartStopMode mode) { FakeFidoDiscovery::StartMode mode) {
next_hid_discovery_ = std::make_unique<FakeFidoDiscovery>( next_hid_discovery_ = std::make_unique<FakeFidoDiscovery>(
U2fTransportProtocol::kUsbHumanInterfaceDevice, mode); U2fTransportProtocol::kUsbHumanInterfaceDevice, mode);
return next_hid_discovery_.get(); return next_hid_discovery_.get();
} }
FakeFidoDiscovery* ScopedFakeFidoDiscoveryFactory::ForgeNextBleDiscovery( FakeFidoDiscovery* ScopedFakeFidoDiscoveryFactory::ForgeNextBleDiscovery(
FakeFidoDiscovery::StartStopMode mode) { FakeFidoDiscovery::StartMode mode) {
next_ble_discovery_ = std::make_unique<FakeFidoDiscovery>( next_ble_discovery_ = std::make_unique<FakeFidoDiscovery>(
U2fTransportProtocol::kBluetoothLowEnergy, mode); U2fTransportProtocol::kBluetoothLowEnergy, mode);
return next_ble_discovery_.get(); return next_ble_discovery_.get();
......
...@@ -51,66 +51,44 @@ namespace test { ...@@ -51,66 +51,44 @@ namespace test {
// // Add devices discovered after doing some heavy lifting. // // Add devices discovered after doing some heavy lifting.
// fake_hid_discovery->AddDevice(std::make_unique<MockFidoDevice>(...)); // fake_hid_discovery->AddDevice(std::make_unique<MockFidoDevice>(...));
// //
// // Run the production code that will eventually stop the discovery. // // Destroy the production instance to eventually stop the discovery.
// //// hid_instance->Stop(); // // hid_instance.reset();
//
// // Wait for discovery to be stopped by the production code, and simulate
// // the discovery starting successfully.
// fake_hid_discovery->WaitForCallToStopAndSimulateSuccess();
// //
class FakeFidoDiscovery : public FidoDiscovery, class FakeFidoDiscovery : public FidoDiscovery,
public base::SupportsWeakPtr<FakeFidoDiscovery> { public base::SupportsWeakPtr<FakeFidoDiscovery> {
public: public:
enum class StartStopMode { enum class StartMode {
// SimulateStarted()/SimualteStopped() needs to be called manually after the // SimulateStarted() needs to be called manually to finish starting the
// production code calls Start()/Stop(). // discovery after the production code calls Start().
kManual, kManual,
// The discovery is automatically and successfully started/stopped once // The discovery is automatically (successfully) started after Start().
// Start()/Stop() is called.
kAutomatic kAutomatic
}; };
explicit FakeFidoDiscovery(U2fTransportProtocol transport, explicit FakeFidoDiscovery(U2fTransportProtocol transport,
StartStopMode mode = StartStopMode::kManual); StartMode mode = StartMode::kManual);
~FakeFidoDiscovery() override; ~FakeFidoDiscovery() override;
// Blocks until start/stop is requested. // Blocks until start is requested.
void WaitForCallToStart(); void WaitForCallToStart();
void WaitForCallToStop();
// Simulates the discovery actually starting/stopping. // Simulates the discovery actually starting.
void SimulateStarted(bool success); void SimulateStarted(bool success);
void SimulateStopped(bool success);
// Combines WaitForCallToStart/Stop + SimulateStarted/Stopped(true). // Combines WaitForCallToStart + SimulateStarted(true).
void WaitForCallToStartAndSimulateSuccess(); void WaitForCallToStartAndSimulateSuccess();
void WaitForCallToStopAndSimulateSuccess();
bool is_start_requested() const { return !start_called_callback_; }
bool is_stop_requested() const { return !stop_called_callback_; }
bool is_running() const { return is_running_; }
// Tests are to directly call Add/RemoveDevice to simulate adding/removing // Tests are to directly call Add/RemoveDevice to simulate adding/removing
// devices. Observers are automatically notified. // devices. Observers are automatically notified.
using FidoDiscovery::AddDevice; using FidoDiscovery::AddDevice;
using FidoDiscovery::RemoveDevice; using FidoDiscovery::RemoveDevice;
// FidoDiscovery:
U2fTransportProtocol GetTransportProtocol() const override;
void Start() override;
void Stop() override;
private: private:
const U2fTransportProtocol transport_; // FidoDiscovery:
void StartInternal() override;
const StartStopMode mode_;
bool is_running_ = false;
const StartMode mode_;
base::RunLoop wait_for_start_loop_; base::RunLoop wait_for_start_loop_;
base::RunLoop wait_for_stop_loop_;
base::OnceClosure start_called_callback_;
base::OnceClosure stop_called_callback_;
DISALLOW_COPY_AND_ASSIGN(FakeFidoDiscovery); DISALLOW_COPY_AND_ASSIGN(FakeFidoDiscovery);
}; };
...@@ -120,7 +98,7 @@ class FakeFidoDiscovery : public FidoDiscovery, ...@@ -120,7 +98,7 @@ class FakeFidoDiscovery : public FidoDiscovery,
class ScopedFakeFidoDiscoveryFactory class ScopedFakeFidoDiscoveryFactory
: public ::device::internal::ScopedFidoDiscoveryFactory { : public ::device::internal::ScopedFidoDiscoveryFactory {
public: public:
using StartStopMode = FakeFidoDiscovery::StartStopMode; using StartMode = FakeFidoDiscovery::StartMode;
ScopedFakeFidoDiscoveryFactory(); ScopedFakeFidoDiscoveryFactory();
~ScopedFakeFidoDiscoveryFactory() override; ~ScopedFakeFidoDiscoveryFactory() override;
...@@ -131,10 +109,8 @@ class ScopedFakeFidoDiscoveryFactory ...@@ -131,10 +109,8 @@ class ScopedFakeFidoDiscoveryFactory
// //
// It is an error not to call the relevant method prior to a call to // It is an error not to call the relevant method prior to a call to
// FidoDiscovery::Create with the respective transport. // FidoDiscovery::Create with the respective transport.
FakeFidoDiscovery* ForgeNextHidDiscovery( FakeFidoDiscovery* ForgeNextHidDiscovery(StartMode mode = StartMode::kManual);
StartStopMode mode = StartStopMode::kManual); FakeFidoDiscovery* ForgeNextBleDiscovery(StartMode mode = StartMode::kManual);
FakeFidoDiscovery* ForgeNextBleDiscovery(
StartStopMode mode = StartStopMode::kManual);
protected: protected:
std::unique_ptr<FidoDiscovery> CreateFidoDiscovery( std::unique_ptr<FidoDiscovery> CreateFidoDiscovery(
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "device/fido/fake_fido_discovery.h" #include "device/fido/fake_fido_discovery.h"
#include <utility>
#include "base/macros.h" #include "base/macros.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
...@@ -34,12 +36,12 @@ using ScopedFakeFidoDiscoveryFactoryTest = FakeFidoDiscoveryTest; ...@@ -34,12 +36,12 @@ using ScopedFakeFidoDiscoveryFactoryTest = FakeFidoDiscoveryTest;
TEST_F(FakeFidoDiscoveryTest, Transport) { TEST_F(FakeFidoDiscoveryTest, Transport) {
FakeFidoDiscovery discovery_ble(U2fTransportProtocol::kBluetoothLowEnergy); FakeFidoDiscovery discovery_ble(U2fTransportProtocol::kBluetoothLowEnergy);
EXPECT_EQ(U2fTransportProtocol::kBluetoothLowEnergy, EXPECT_EQ(U2fTransportProtocol::kBluetoothLowEnergy,
discovery_ble.GetTransportProtocol()); discovery_ble.transport());
FakeFidoDiscovery discovery_hid( FakeFidoDiscovery discovery_hid(
U2fTransportProtocol::kUsbHumanInterfaceDevice); U2fTransportProtocol::kUsbHumanInterfaceDevice);
EXPECT_EQ(U2fTransportProtocol::kUsbHumanInterfaceDevice, EXPECT_EQ(U2fTransportProtocol::kUsbHumanInterfaceDevice,
discovery_hid.GetTransportProtocol()); discovery_hid.transport());
} }
TEST_F(FakeFidoDiscoveryTest, InitialState) { TEST_F(FakeFidoDiscoveryTest, InitialState) {
...@@ -47,49 +49,30 @@ TEST_F(FakeFidoDiscoveryTest, InitialState) { ...@@ -47,49 +49,30 @@ TEST_F(FakeFidoDiscoveryTest, InitialState) {
ASSERT_FALSE(discovery.is_running()); ASSERT_FALSE(discovery.is_running());
ASSERT_FALSE(discovery.is_start_requested()); ASSERT_FALSE(discovery.is_start_requested());
ASSERT_FALSE(discovery.is_stop_requested());
} }
TEST_F(FakeFidoDiscoveryTest, StartStopDiscovery) { TEST_F(FakeFidoDiscoveryTest, StartDiscovery) {
FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy); FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
discovery.Start(); discovery.Start();
ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested()); ASSERT_TRUE(discovery.is_start_requested());
ASSERT_FALSE(discovery.is_stop_requested()); ASSERT_FALSE(discovery.is_running());
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true)); EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.WaitForCallToStartAndSimulateSuccess(); discovery.WaitForCallToStartAndSimulateSuccess();
::testing::Mock::VerifyAndClearExpectations(&observer);
ASSERT_TRUE(discovery.is_running()); ASSERT_TRUE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested()); ASSERT_TRUE(discovery.is_start_requested());
ASSERT_FALSE(discovery.is_stop_requested());
discovery.Stop();
ASSERT_TRUE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
ASSERT_TRUE(discovery.is_stop_requested());
EXPECT_CALL(observer, DiscoveryStopped(&discovery, true));
discovery.WaitForCallToStopAndSimulateSuccess();
::testing::Mock::VerifyAndClearExpectations(&observer);
ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
ASSERT_TRUE(discovery.is_stop_requested());
} }
TEST_F(FakeFidoDiscoveryTest, WaitThenStartStopDiscovery) { TEST_F(FakeFidoDiscoveryTest, WaitThenStartStopDiscovery) {
FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy); FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() { discovery.Start(); })); FROM_HERE, base::BindLambdaForTesting([&]() { discovery.Start(); }));
...@@ -98,32 +81,11 @@ TEST_F(FakeFidoDiscoveryTest, WaitThenStartStopDiscovery) { ...@@ -98,32 +81,11 @@ TEST_F(FakeFidoDiscoveryTest, WaitThenStartStopDiscovery) {
ASSERT_FALSE(discovery.is_running()); ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested()); ASSERT_TRUE(discovery.is_start_requested());
ASSERT_FALSE(discovery.is_stop_requested());
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true)); EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.SimulateStarted(true); discovery.SimulateStarted(true);
::testing::Mock::VerifyAndClearExpectations(&observer);
ASSERT_TRUE(discovery.is_running()); ASSERT_TRUE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested()); ASSERT_TRUE(discovery.is_start_requested());
ASSERT_FALSE(discovery.is_stop_requested());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() { discovery.Stop(); }));
discovery.WaitForCallToStop();
ASSERT_TRUE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
ASSERT_TRUE(discovery.is_stop_requested());
EXPECT_CALL(observer, DiscoveryStopped(&discovery, true));
discovery.SimulateStopped(true);
::testing::Mock::VerifyAndClearExpectations(&observer);
ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
ASSERT_TRUE(discovery.is_stop_requested());
} }
// Starting discovery and failing: instance stays in "not running" state // Starting discovery and failing: instance stays in "not running" state
...@@ -131,45 +93,17 @@ TEST_F(FakeFidoDiscoveryTest, StartFail) { ...@@ -131,45 +93,17 @@ TEST_F(FakeFidoDiscoveryTest, StartFail) {
FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy); FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
discovery.Start(); discovery.Start();
EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
discovery.SimulateStarted(false);
::testing::Mock::VerifyAndClearExpectations(&observer);
ASSERT_FALSE(discovery.is_running()); ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested()); ASSERT_TRUE(discovery.is_start_requested());
ASSERT_FALSE(discovery.is_stop_requested());
}
// Stopping discovery and failing: instance stays in a "running" state.
TEST_F(FakeFidoDiscoveryTest, StopFail) {
FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer);
discovery.Start();
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.SimulateStarted(true);
::testing::Mock::VerifyAndClearExpectations(&observer);
ASSERT_TRUE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
ASSERT_FALSE(discovery.is_stop_requested());
discovery.Stop();
EXPECT_CALL(observer, DiscoveryStopped(&discovery, false)); EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
discovery.SimulateStopped(false); discovery.SimulateStarted(false);
::testing::Mock::VerifyAndClearExpectations(&observer); ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested()); ASSERT_TRUE(discovery.is_start_requested());
ASSERT_TRUE(discovery.is_stop_requested());
} }
// Adding device is possible both before and after discovery actually starts. // Adding device is possible both before and after discovery actually starts.
...@@ -177,7 +111,7 @@ TEST_F(FakeFidoDiscoveryTest, AddDevice) { ...@@ -177,7 +111,7 @@ TEST_F(FakeFidoDiscoveryTest, AddDevice) {
FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy); FakeFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
discovery.Start(); discovery.Start();
...@@ -204,7 +138,7 @@ TEST_F(ScopedFakeFidoDiscoveryFactoryTest, ...@@ -204,7 +138,7 @@ TEST_F(ScopedFakeFidoDiscoveryFactoryTest,
ScopedFakeFidoDiscoveryFactory factory; ScopedFakeFidoDiscoveryFactory factory;
auto* injected_fake_discovery = factory.ForgeNextHidDiscovery(); auto* injected_fake_discovery = factory.ForgeNextHidDiscovery();
ASSERT_EQ(U2fTransportProtocol::kUsbHumanInterfaceDevice, ASSERT_EQ(U2fTransportProtocol::kUsbHumanInterfaceDevice,
injected_fake_discovery->GetTransportProtocol()); injected_fake_discovery->transport());
auto produced_discovery = FidoDiscovery::Create( auto produced_discovery = FidoDiscovery::Create(
U2fTransportProtocol::kUsbHumanInterfaceDevice, nullptr); U2fTransportProtocol::kUsbHumanInterfaceDevice, nullptr);
EXPECT_TRUE(produced_discovery); EXPECT_TRUE(produced_discovery);
...@@ -218,14 +152,14 @@ TEST_F(ScopedFakeFidoDiscoveryFactoryTest, ...@@ -218,14 +152,14 @@ TEST_F(ScopedFakeFidoDiscoveryFactoryTest,
auto* injected_fake_discovery_1 = factory.ForgeNextBleDiscovery(); auto* injected_fake_discovery_1 = factory.ForgeNextBleDiscovery();
ASSERT_EQ(U2fTransportProtocol::kBluetoothLowEnergy, ASSERT_EQ(U2fTransportProtocol::kBluetoothLowEnergy,
injected_fake_discovery_1->GetTransportProtocol()); injected_fake_discovery_1->transport());
auto produced_discovery_1 = auto produced_discovery_1 =
FidoDiscovery::Create(U2fTransportProtocol::kBluetoothLowEnergy, nullptr); FidoDiscovery::Create(U2fTransportProtocol::kBluetoothLowEnergy, nullptr);
EXPECT_EQ(injected_fake_discovery_1, produced_discovery_1.get()); EXPECT_EQ(injected_fake_discovery_1, produced_discovery_1.get());
auto* injected_fake_discovery_2 = factory.ForgeNextBleDiscovery(); auto* injected_fake_discovery_2 = factory.ForgeNextBleDiscovery();
ASSERT_EQ(U2fTransportProtocol::kBluetoothLowEnergy, ASSERT_EQ(U2fTransportProtocol::kBluetoothLowEnergy,
injected_fake_discovery_2->GetTransportProtocol()); injected_fake_discovery_2->transport());
auto produced_discovery_2 = auto produced_discovery_2 =
FidoDiscovery::Create(U2fTransportProtocol::kBluetoothLowEnergy, nullptr); FidoDiscovery::Create(U2fTransportProtocol::kBluetoothLowEnergy, nullptr);
EXPECT_EQ(injected_fake_discovery_2, produced_discovery_2.get()); EXPECT_EQ(injected_fake_discovery_2, produced_discovery_2.get());
......
...@@ -8,8 +8,11 @@ ...@@ -8,8 +8,11 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/location.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_common.h" #include "device/bluetooth/bluetooth_common.h"
#include "device/bluetooth/bluetooth_discovery_filter.h" #include "device/bluetooth/bluetooth_discovery_filter.h"
...@@ -20,37 +23,14 @@ ...@@ -20,37 +23,14 @@
namespace device { namespace device {
FidoBleDiscovery::FidoBleDiscovery() : weak_factory_(this) {} FidoBleDiscovery::FidoBleDiscovery()
: FidoDiscovery(U2fTransportProtocol::kBluetoothLowEnergy),
weak_factory_(this) {}
FidoBleDiscovery::~FidoBleDiscovery() { FidoBleDiscovery::~FidoBleDiscovery() {
if (adapter_) if (adapter_)
adapter_->RemoveObserver(this); adapter_->RemoveObserver(this);
// Pretend we are able to successfully stop a discovery session in case it is // Destroying |discovery_session_| will best-effort-stop discovering.
// still present.
if (discovery_session_)
OnStopped(true);
}
U2fTransportProtocol FidoBleDiscovery::GetTransportProtocol() const {
return U2fTransportProtocol::kBluetoothLowEnergy;
}
void FidoBleDiscovery::Start() {
auto& factory = BluetoothAdapterFactory::Get();
factory.GetAdapter(
base::Bind(&FidoBleDiscovery::OnGetAdapter, weak_factory_.GetWeakPtr()));
}
void FidoBleDiscovery::Stop() {
DCHECK(adapter_);
adapter_->RemoveObserver(this);
DCHECK(discovery_session_);
discovery_session_->Stop(base::Bind(&FidoBleDiscovery::OnStopped,
weak_factory_.GetWeakPtr(), true),
base::Bind(&FidoBleDiscovery::OnStopped,
weak_factory_.GetWeakPtr(), false));
} }
// static // static
...@@ -117,6 +97,26 @@ void FidoBleDiscovery::OnStartDiscoverySessionWithFilterError() { ...@@ -117,6 +97,26 @@ void FidoBleDiscovery::OnStartDiscoverySessionWithFilterError() {
NotifyDiscoveryStarted(false); NotifyDiscoveryStarted(false);
} }
void FidoBleDiscovery::StartInternal() {
auto& factory = BluetoothAdapterFactory::Get();
auto callback = base::BindRepeating(&FidoBleDiscovery::OnGetAdapter,
weak_factory_.GetWeakPtr());
#if defined(OS_MACOSX)
// BluetoothAdapter may invoke the callback synchronously on Mac, but
// StartInternal() never wants to invoke to NotifyDiscoveryStarted()
// immediately, so ensure there is at least post-task at this bottleneck.
// See: https://crbug.com/823686.
callback = base::BindRepeating(
[](BluetoothAdapterFactory::AdapterCallback callback,
scoped_refptr<BluetoothAdapter> adapter) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindRepeating(callback, adapter));
},
std::move(callback));
#endif // defined(OS_MACOSX)
factory.GetAdapter(std::move(callback));
}
void FidoBleDiscovery::DeviceAdded(BluetoothAdapter* adapter, void FidoBleDiscovery::DeviceAdded(BluetoothAdapter* adapter,
BluetoothDevice* device) { BluetoothDevice* device) {
if (base::ContainsKey(device->GetUUIDs(), FidoServiceUUID())) { if (base::ContainsKey(device->GetUUIDs(), FidoServiceUUID())) {
...@@ -143,9 +143,4 @@ void FidoBleDiscovery::DeviceRemoved(BluetoothAdapter* adapter, ...@@ -143,9 +143,4 @@ void FidoBleDiscovery::DeviceRemoved(BluetoothAdapter* adapter,
} }
} }
void FidoBleDiscovery::OnStopped(bool success) {
discovery_session_.reset();
NotifyDiscoveryStopped(success);
}
} // namespace device } // namespace device
...@@ -27,11 +27,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery ...@@ -27,11 +27,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery
FidoBleDiscovery(); FidoBleDiscovery();
~FidoBleDiscovery() override; ~FidoBleDiscovery() override;
// FidoDiscovery:
U2fTransportProtocol GetTransportProtocol() const override;
void Start() override;
void Stop() override;
private: private:
static const BluetoothUUID& FidoServiceUUID(); static const BluetoothUUID& FidoServiceUUID();
...@@ -42,13 +37,15 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery ...@@ -42,13 +37,15 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery
std::unique_ptr<BluetoothDiscoverySession>); std::unique_ptr<BluetoothDiscoverySession>);
void OnStartDiscoverySessionWithFilterError(); void OnStartDiscoverySessionWithFilterError();
// FidoDiscovery:
void StartInternal() override;
// BluetoothAdapter::Observer: // BluetoothAdapter::Observer:
void DeviceAdded(BluetoothAdapter* adapter, BluetoothDevice* device) override; void DeviceAdded(BluetoothAdapter* adapter, BluetoothDevice* device) override;
void DeviceChanged(BluetoothAdapter* adapter, void DeviceChanged(BluetoothAdapter* adapter,
BluetoothDevice* device) override; BluetoothDevice* device) override;
void DeviceRemoved(BluetoothAdapter* adapter, void DeviceRemoved(BluetoothAdapter* adapter,
BluetoothDevice* device) override; BluetoothDevice* device) override;
void OnStopped(bool success);
scoped_refptr<BluetoothAdapter> adapter_; scoped_refptr<BluetoothAdapter> adapter_;
std::unique_ptr<BluetoothDiscoverySession> discovery_session_; std::unique_ptr<BluetoothDiscoverySession> discovery_session_;
......
...@@ -45,9 +45,8 @@ TEST_F(BluetoothTest, FidoBleDiscoveryNoAdapter) { ...@@ -45,9 +45,8 @@ TEST_F(BluetoothTest, FidoBleDiscoveryNoAdapter) {
// We don't expect any calls to the notification methods. // We don't expect any calls to the notification methods.
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
EXPECT_CALL(observer, DiscoveryStarted(&discovery, _)).Times(0); EXPECT_CALL(observer, DiscoveryStarted(&discovery, _)).Times(0);
EXPECT_CALL(observer, DiscoveryStopped(&discovery, _)).Times(0);
EXPECT_CALL(observer, DeviceAdded(&discovery, _)).Times(0); EXPECT_CALL(observer, DeviceAdded(&discovery, _)).Times(0);
EXPECT_CALL(observer, DeviceRemoved(&discovery, _)).Times(0); EXPECT_CALL(observer, DeviceRemoved(&discovery, _)).Times(0);
} }
...@@ -63,8 +62,9 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsKnownDevice) { ...@@ -63,8 +62,9 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsKnownDevice) {
SimulateLowEnergyDevice(7); SimulateLowEnergyDevice(7);
FidoBleDiscovery discovery; FidoBleDiscovery discovery;
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
...@@ -78,19 +78,6 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsKnownDevice) { ...@@ -78,19 +78,6 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsKnownDevice) {
discovery.Start(); discovery.Start();
run_loop.Run(); run_loop.Run();
} }
// TODO(crbug/763303): Delete device and check OnDeviceDeleted invocation.
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
EXPECT_CALL(observer, DiscoveryStopped(&discovery, true))
.WillOnce(ReturnFromAsyncCall(quit));
discovery.Stop();
run_loop.Run();
}
} }
TEST_F(BluetoothTest, FidoBleDiscoveryFindsNewDevice) { TEST_F(BluetoothTest, FidoBleDiscoveryFindsNewDevice) {
...@@ -102,7 +89,7 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsNewDevice) { ...@@ -102,7 +89,7 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsNewDevice) {
FidoBleDiscovery discovery; FidoBleDiscovery discovery;
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
...@@ -127,17 +114,6 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsNewDevice) { ...@@ -127,17 +114,6 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsNewDevice) {
run_loop.Run(); run_loop.Run();
} }
// TODO(crbug/763303): Delete device and check OnDeviceDeleted invocation.
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
EXPECT_CALL(observer, DiscoveryStopped(&discovery, true))
.WillOnce(ReturnFromAsyncCall(quit));
discovery.Stop();
run_loop.Run();
}
} }
// Simulate the scenario where the BLE device is already known at start-up time, // Simulate the scenario where the BLE device is already known at start-up time,
...@@ -156,7 +132,7 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsUpdatedDevice) { ...@@ -156,7 +132,7 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsUpdatedDevice) {
FidoBleDiscovery discovery; FidoBleDiscovery discovery;
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
{ {
base::RunLoop run_loop; base::RunLoop run_loop;
...@@ -188,17 +164,6 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsUpdatedDevice) { ...@@ -188,17 +164,6 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsUpdatedDevice) {
EXPECT_EQ(FidoBleDevice::GetId(BluetoothTestBase::kTestDeviceAddress1), EXPECT_EQ(FidoBleDevice::GetId(BluetoothTestBase::kTestDeviceAddress1),
devices[0]->GetId()); devices[0]->GetId());
} }
// TODO(crbug/763303): Delete device and check OnDeviceDeleted invocation.
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
EXPECT_CALL(observer, DiscoveryStopped(&discovery, true))
.WillOnce(ReturnFromAsyncCall(quit));
discovery.Stop();
run_loop.Run();
}
} }
} // namespace device } // namespace device
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include <utility> #include <utility>
#include "base/logging.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "device/fido/fido_ble_discovery.h" #include "device/fido/fido_ble_discovery.h"
#include "device/fido/fido_device.h" #include "device/fido/fido_device.h"
...@@ -39,7 +38,7 @@ std::unique_ptr<FidoDiscovery> CreateFidoDiscoveryImpl( ...@@ -39,7 +38,7 @@ std::unique_ptr<FidoDiscovery> CreateFidoDiscoveryImpl(
} }
DCHECK(discovery); DCHECK(discovery);
DCHECK_EQ(discovery->GetTransportProtocol(), transport); DCHECK_EQ(discovery->transport(), transport);
return discovery; return discovery;
} }
...@@ -58,36 +57,40 @@ std::unique_ptr<FidoDiscovery> FidoDiscovery::Create( ...@@ -58,36 +57,40 @@ std::unique_ptr<FidoDiscovery> FidoDiscovery::Create(
return (*g_factory_func_)(transport, connector); return (*g_factory_func_)(transport, connector);
} }
FidoDiscovery::FidoDiscovery() = default; FidoDiscovery::FidoDiscovery(U2fTransportProtocol transport)
: transport_(transport) {}
FidoDiscovery::~FidoDiscovery() = default; FidoDiscovery::~FidoDiscovery() = default;
void FidoDiscovery::AddObserver(Observer* observer) { void FidoDiscovery::Start() {
observers_.AddObserver(observer); DCHECK_EQ(state_, State::kIdle);
} state_ = State::kStarting;
StartInternal();
void FidoDiscovery::RemoveObserver(Observer* observer) { // StartInternal should never synchronously call NotifyStarted().
observers_.RemoveObserver(observer); DCHECK_EQ(state_, State::kStarting);
} }
void FidoDiscovery::NotifyDiscoveryStarted(bool success) { void FidoDiscovery::NotifyDiscoveryStarted(bool success) {
for (auto& observer : observers_) DCHECK_EQ(state_, State::kStarting);
observer.DiscoveryStarted(this, success); if (success)
} state_ = State::kRunning;
if (!observer_)
void FidoDiscovery::NotifyDiscoveryStopped(bool success) { return;
for (auto& observer : observers_) observer_->DiscoveryStarted(this, success);
observer.DiscoveryStopped(this, success);
} }
void FidoDiscovery::NotifyDeviceAdded(FidoDevice* device) { void FidoDiscovery::NotifyDeviceAdded(FidoDevice* device) {
for (auto& observer : observers_) DCHECK_NE(state_, State::kIdle);
observer.DeviceAdded(this, device); if (!observer_)
return;
observer_->DeviceAdded(this, device);
} }
void FidoDiscovery::NotifyDeviceRemoved(FidoDevice* device) { void FidoDiscovery::NotifyDeviceRemoved(FidoDevice* device) {
for (auto& observer : observers_) DCHECK_NE(state_, State::kIdle);
observer.DeviceRemoved(this, device); if (!observer_)
return;
observer_->DeviceRemoved(this, device);
} }
std::vector<FidoDevice*> FidoDiscovery::GetDevices() { std::vector<FidoDevice*> FidoDiscovery::GetDevices() {
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
#include <vector> #include <vector>
#include "base/component_export.h" #include "base/component_export.h"
#include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "device/fido/u2f_transport_protocol.h" #include "device/fido/u2f_transport_protocol.h"
...@@ -32,11 +32,23 @@ class ScopedFidoDiscoveryFactory; ...@@ -32,11 +32,23 @@ class ScopedFidoDiscoveryFactory;
class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery { class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery {
public: public:
enum class State {
kIdle,
kStarting,
kRunning,
};
class COMPONENT_EXPORT(DEVICE_FIDO) Observer { class COMPONENT_EXPORT(DEVICE_FIDO) Observer {
public: public:
virtual ~Observer(); virtual ~Observer();
// It is guaranteed that this is never invoked synchronously from Start().
virtual void DiscoveryStarted(FidoDiscovery* discovery, bool success) = 0; virtual void DiscoveryStarted(FidoDiscovery* discovery, bool success) = 0;
virtual void DiscoveryStopped(FidoDiscovery* discovery, bool success) = 0;
// It is guaranteed that DeviceAdded/DeviceRemoved() will not be invoked
// before the client of FidoDiscovery calls FidoDiscovery::Start(). However,
// for devices already known to the system at that point, DeviceAdded()
// might already be called to reported already known devices.
virtual void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) = 0; virtual void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) = 0;
virtual void DeviceRemoved(FidoDiscovery* discovery, virtual void DeviceRemoved(FidoDiscovery* discovery,
FidoDevice* device) = 0; FidoDevice* device) = 0;
...@@ -53,17 +65,17 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery { ...@@ -53,17 +65,17 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery {
virtual ~FidoDiscovery(); virtual ~FidoDiscovery();
virtual U2fTransportProtocol GetTransportProtocol() const = 0; Observer* observer() const { return observer_; }
virtual void Start() = 0; void set_observer(Observer* observer) {
virtual void Stop() = 0; DCHECK(!observer_ || !observer) << "Only one observer is supported.";
observer_ = observer;
}
void AddObserver(Observer* observer); U2fTransportProtocol transport() const { return transport_; }
void RemoveObserver(Observer* observer); bool is_start_requested() const { return state_ != State::kIdle; }
bool is_running() const { return state_ == State::kRunning; }
void NotifyDiscoveryStarted(bool success); void Start();
void NotifyDiscoveryStopped(bool success);
void NotifyDeviceAdded(FidoDevice* device);
void NotifyDeviceRemoved(FidoDevice* device);
std::vector<FidoDevice*> GetDevices(); std::vector<FidoDevice*> GetDevices();
std::vector<const FidoDevice*> GetDevices() const; std::vector<const FidoDevice*> GetDevices() const;
...@@ -72,13 +84,24 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery { ...@@ -72,13 +84,24 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery {
const FidoDevice* GetDevice(base::StringPiece device_id) const; const FidoDevice* GetDevice(base::StringPiece device_id) const;
protected: protected:
FidoDiscovery(); FidoDiscovery(U2fTransportProtocol transport);
virtual bool AddDevice(std::unique_ptr<FidoDevice> device); void NotifyDiscoveryStarted(bool success);
virtual bool RemoveDevice(base::StringPiece device_id); void NotifyDeviceAdded(FidoDevice* device);
void NotifyDeviceRemoved(FidoDevice* device);
bool AddDevice(std::unique_ptr<FidoDevice> device);
bool RemoveDevice(base::StringPiece device_id);
// Subclasses should implement this to actually start the discovery when it is
// requested.
//
// The implementation should asynchronously invoke NotifyDiscoveryStarted when
// the discovery is s tarted.
virtual void StartInternal() = 0;
std::map<std::string, std::unique_ptr<FidoDevice>, std::less<>> devices_; std::map<std::string, std::unique_ptr<FidoDevice>, std::less<>> devices_;
base::ObserverList<Observer> observers_; Observer* observer_ = nullptr;
private: private:
friend class internal::ScopedFidoDiscoveryFactory; friend class internal::ScopedFidoDiscoveryFactory;
...@@ -87,6 +110,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery { ...@@ -87,6 +110,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery {
using FactoryFuncPtr = decltype(&Create); using FactoryFuncPtr = decltype(&Create);
static FactoryFuncPtr g_factory_func_; static FactoryFuncPtr g_factory_func_;
const U2fTransportProtocol transport_;
State state_ = State::kIdle;
DISALLOW_COPY_AND_ASSIGN(FidoDiscovery); DISALLOW_COPY_AND_ASSIGN(FidoDiscovery);
}; };
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "device/fido/fido_discovery.h"
#include <utility> #include <utility>
#include "base/macros.h" #include "base/macros.h"
#include "device/fido/fido_discovery.h"
#include "device/fido/mock_fido_device.h" #include "device/fido/mock_fido_device.h"
#include "device/fido/mock_fido_discovery_observer.h" #include "device/fido/mock_fido_discovery_observer.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
...@@ -22,20 +23,18 @@ using ::testing::UnorderedElementsAre; ...@@ -22,20 +23,18 @@ using ::testing::UnorderedElementsAre;
// A minimal implementation of FidoDiscovery that is no longer abstract. // A minimal implementation of FidoDiscovery that is no longer abstract.
class ConcreteFidoDiscovery : public FidoDiscovery { class ConcreteFidoDiscovery : public FidoDiscovery {
public: public:
ConcreteFidoDiscovery() = default; explicit ConcreteFidoDiscovery(U2fTransportProtocol transport)
: FidoDiscovery(transport) {}
~ConcreteFidoDiscovery() override = default; ~ConcreteFidoDiscovery() override = default;
MOCK_METHOD0(StartInternal, void());
using FidoDiscovery::AddDevice; using FidoDiscovery::AddDevice;
using FidoDiscovery::RemoveDevice; using FidoDiscovery::RemoveDevice;
const base::ObserverList<Observer>& observers() const { return observers_; } using FidoDiscovery::NotifyDiscoveryStarted;
using FidoDiscovery::NotifyDeviceAdded;
protected: using FidoDiscovery::NotifyDeviceRemoved;
U2fTransportProtocol GetTransportProtocol() const override {
return U2fTransportProtocol::kUsbHumanInterfaceDevice;
}
void Start() override {}
void Stop() override {}
private: private:
DISALLOW_COPY_AND_ASSIGN(ConcreteFidoDiscovery); DISALLOW_COPY_AND_ASSIGN(ConcreteFidoDiscovery);
...@@ -44,46 +43,57 @@ class ConcreteFidoDiscovery : public FidoDiscovery { ...@@ -44,46 +43,57 @@ class ConcreteFidoDiscovery : public FidoDiscovery {
} // namespace } // namespace
TEST(FidoDiscoveryTest, TestAddAndRemoveObserver) { TEST(FidoDiscoveryTest, TestAddAndRemoveObserver) {
ConcreteFidoDiscovery discovery; ConcreteFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
EXPECT_FALSE(discovery.observers().HasObserver(&observer)); EXPECT_EQ(nullptr, discovery.observer());
discovery.AddObserver(&observer);
EXPECT_TRUE(discovery.observers().HasObserver(&observer)); discovery.set_observer(&observer);
EXPECT_EQ(&observer, discovery.observer());
discovery.RemoveObserver(&observer); discovery.set_observer(nullptr);
EXPECT_FALSE(discovery.observers().HasObserver(&observer)); EXPECT_EQ(nullptr, discovery.observer());
} }
TEST(FidoDiscoveryTest, TestNotifications) { TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
ConcreteFidoDiscovery discovery; ConcreteFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true)); EXPECT_FALSE(discovery.is_start_requested());
discovery.NotifyDiscoveryStarted(true); EXPECT_FALSE(discovery.is_running());
EXPECT_CALL(observer, DiscoveryStarted(&discovery, false)); EXPECT_CALL(discovery, StartInternal());
discovery.NotifyDiscoveryStarted(false); discovery.Start();
EXPECT_TRUE(discovery.is_start_requested());
EXPECT_FALSE(discovery.is_running());
::testing::Mock::VerifyAndClearExpectations(&discovery);
EXPECT_CALL(observer, DiscoveryStopped(&discovery, true)); EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.NotifyDiscoveryStopped(true); discovery.NotifyDiscoveryStarted(true);
EXPECT_TRUE(discovery.is_start_requested());
EXPECT_TRUE(discovery.is_running());
::testing::Mock::VerifyAndClearExpectations(&observer);
}
EXPECT_CALL(observer, DiscoveryStopped(&discovery, false)); TEST(FidoDiscoveryTest, TestNotificationsOnFailedStart) {
discovery.NotifyDiscoveryStopped(false); ConcreteFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer;
discovery.set_observer(&observer);
MockFidoDevice device; discovery.Start();
EXPECT_CALL(observer, DeviceAdded(&discovery, &device));
discovery.NotifyDeviceAdded(&device);
EXPECT_CALL(observer, DeviceRemoved(&discovery, &device)); EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
discovery.NotifyDeviceRemoved(&device); discovery.NotifyDiscoveryStarted(false);
EXPECT_TRUE(discovery.is_start_requested());
EXPECT_FALSE(discovery.is_running());
::testing::Mock::VerifyAndClearExpectations(&observer);
} }
TEST(FidoDiscoveryTest, TestAddRemoveDevices) { TEST(FidoDiscoveryTest, TestAddRemoveDevices) {
ConcreteFidoDiscovery discovery; ConcreteFidoDiscovery discovery(U2fTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.AddObserver(&observer); discovery.set_observer(&observer);
discovery.Start();
// Expect successful insertion. // Expect successful insertion.
auto device0 = std::make_unique<MockFidoDevice>(); auto device0 = std::make_unique<MockFidoDevice>();
...@@ -91,6 +101,7 @@ TEST(FidoDiscoveryTest, TestAddRemoveDevices) { ...@@ -91,6 +101,7 @@ TEST(FidoDiscoveryTest, TestAddRemoveDevices) {
EXPECT_CALL(observer, DeviceAdded(&discovery, device0_raw)); EXPECT_CALL(observer, DeviceAdded(&discovery, device0_raw));
EXPECT_CALL(*device0, GetId()).WillOnce(Return("device0")); EXPECT_CALL(*device0, GetId()).WillOnce(Return("device0"));
EXPECT_TRUE(discovery.AddDevice(std::move(device0))); EXPECT_TRUE(discovery.AddDevice(std::move(device0)));
::testing::Mock::VerifyAndClearExpectations(&observer);
// // Expect successful insertion. // // Expect successful insertion.
auto device1 = std::make_unique<MockFidoDevice>(); auto device1 = std::make_unique<MockFidoDevice>();
...@@ -98,12 +109,14 @@ TEST(FidoDiscoveryTest, TestAddRemoveDevices) { ...@@ -98,12 +109,14 @@ TEST(FidoDiscoveryTest, TestAddRemoveDevices) {
EXPECT_CALL(observer, DeviceAdded(&discovery, device1_raw)); EXPECT_CALL(observer, DeviceAdded(&discovery, device1_raw));
EXPECT_CALL(*device1, GetId()).WillOnce(Return("device1")); EXPECT_CALL(*device1, GetId()).WillOnce(Return("device1"));
EXPECT_TRUE(discovery.AddDevice(std::move(device1))); EXPECT_TRUE(discovery.AddDevice(std::move(device1)));
::testing::Mock::VerifyAndClearExpectations(&observer);
// Inserting a device with an already present id should be prevented. // Inserting a device with an already present id should be prevented.
auto device1_dup = std::make_unique<MockFidoDevice>(); auto device1_dup = std::make_unique<MockFidoDevice>();
EXPECT_CALL(observer, DeviceAdded(_, _)).Times(0); EXPECT_CALL(observer, DeviceAdded(_, _)).Times(0);
EXPECT_CALL(*device1_dup, GetId()).WillOnce(Return("device1")); EXPECT_CALL(*device1_dup, GetId()).WillOnce(Return("device1"));
EXPECT_FALSE(discovery.AddDevice(std::move(device1_dup))); EXPECT_FALSE(discovery.AddDevice(std::move(device1_dup)));
::testing::Mock::VerifyAndClearExpectations(&observer);
EXPECT_EQ(device0_raw, discovery.GetDevice("device0")); EXPECT_EQ(device0_raw, discovery.GetDevice("device0"));
EXPECT_EQ(device1_raw, discovery.GetDevice("device1")); EXPECT_EQ(device1_raw, discovery.GetDevice("device1"));
...@@ -119,12 +132,15 @@ TEST(FidoDiscoveryTest, TestAddRemoveDevices) { ...@@ -119,12 +132,15 @@ TEST(FidoDiscoveryTest, TestAddRemoveDevices) {
// Trying to remove a non-present device should fail. // Trying to remove a non-present device should fail.
EXPECT_CALL(observer, DeviceRemoved(_, _)).Times(0); EXPECT_CALL(observer, DeviceRemoved(_, _)).Times(0);
EXPECT_FALSE(discovery.RemoveDevice("device2")); EXPECT_FALSE(discovery.RemoveDevice("device2"));
::testing::Mock::VerifyAndClearExpectations(&observer);
EXPECT_CALL(observer, DeviceRemoved(&discovery, device1_raw)); EXPECT_CALL(observer, DeviceRemoved(&discovery, device1_raw));
EXPECT_TRUE(discovery.RemoveDevice("device1")); EXPECT_TRUE(discovery.RemoveDevice("device1"));
::testing::Mock::VerifyAndClearExpectations(&observer);
EXPECT_CALL(observer, DeviceRemoved(&discovery, device0_raw)); EXPECT_CALL(observer, DeviceRemoved(&discovery, device0_raw));
EXPECT_TRUE(discovery.RemoveDevice("device0")); EXPECT_TRUE(discovery.RemoveDevice("device0"));
::testing::Mock::VerifyAndClearExpectations(&observer);
} }
} // namespace device } // namespace device
...@@ -14,18 +14,17 @@ ...@@ -14,18 +14,17 @@
namespace device { namespace device {
FidoHidDiscovery::FidoHidDiscovery(::service_manager::Connector* connector) FidoHidDiscovery::FidoHidDiscovery(::service_manager::Connector* connector)
: connector_(connector), binding_(this), weak_factory_(this) { : FidoDiscovery(U2fTransportProtocol::kUsbHumanInterfaceDevice),
connector_(connector),
binding_(this),
weak_factory_(this) {
// TODO(piperc@): Give this constant a name. // TODO(piperc@): Give this constant a name.
filter_.SetUsagePage(0xf1d0); filter_.SetUsagePage(0xf1d0);
} }
FidoHidDiscovery::~FidoHidDiscovery() = default; FidoHidDiscovery::~FidoHidDiscovery() = default;
U2fTransportProtocol FidoHidDiscovery::GetTransportProtocol() const { void FidoHidDiscovery::StartInternal() {
return U2fTransportProtocol::kUsbHumanInterfaceDevice;
}
void FidoHidDiscovery::Start() {
DCHECK(connector_); DCHECK(connector_);
connector_->BindInterface(device::mojom::kServiceName, connector_->BindInterface(device::mojom::kServiceName,
mojo::MakeRequest(&hid_manager_)); mojo::MakeRequest(&hid_manager_));
...@@ -36,10 +35,6 @@ void FidoHidDiscovery::Start() { ...@@ -36,10 +35,6 @@ void FidoHidDiscovery::Start() {
std::move(client), base::BindOnce(&FidoHidDiscovery::OnGetDevices, std::move(client), base::BindOnce(&FidoHidDiscovery::OnGetDevices,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
void FidoHidDiscovery::Stop() {
binding_.Unbind();
NotifyDiscoveryStopped(true);
}
void FidoHidDiscovery::DeviceAdded( void FidoHidDiscovery::DeviceAdded(
device::mojom::HidDeviceInfoPtr device_info) { device::mojom::HidDeviceInfoPtr device_info) {
......
...@@ -32,12 +32,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidDiscovery ...@@ -32,12 +32,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidDiscovery
explicit FidoHidDiscovery(::service_manager::Connector* connector); explicit FidoHidDiscovery(::service_manager::Connector* connector);
~FidoHidDiscovery() override; ~FidoHidDiscovery() override;
private:
// FidoDiscovery: // FidoDiscovery:
U2fTransportProtocol GetTransportProtocol() const override; void StartInternal() override;
void Start() override;
void Stop() override;
private:
// device::mojom::HidManagerClient implementation: // device::mojom::HidManagerClient implementation:
void DeviceAdded(device::mojom::HidDeviceInfoPtr device_info) override; void DeviceAdded(device::mojom::HidDeviceInfoPtr device_info) override;
void DeviceRemoved(device::mojom::HidDeviceInfoPtr device_info) override; void DeviceRemoved(device::mojom::HidDeviceInfoPtr device_info) override;
......
...@@ -86,7 +86,7 @@ TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) { ...@@ -86,7 +86,7 @@ TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
fake_hid_manager_->AddDevice(MakeFidoHidDevice("known")); fake_hid_manager_->AddDevice(MakeFidoHidDevice("known"));
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true)); EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.AddObserver(&observer); discovery.set_observer(&observer);
discovery.Start(); discovery.Start();
// Devices initially known to the service before discovery started should be // Devices initially known to the service before discovery started should be
......
...@@ -4,7 +4,13 @@ ...@@ -4,7 +4,13 @@
#include "device/fido/scoped_virtual_u2f_device.h" #include "device/fido/scoped_virtual_u2f_device.h"
#include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace device { namespace device {
namespace test { namespace test {
...@@ -12,19 +18,22 @@ namespace test { ...@@ -12,19 +18,22 @@ namespace test {
// A FidoDiscovery that always vends a single |VirtualU2fDevice|. // A FidoDiscovery that always vends a single |VirtualU2fDevice|.
class VirtualU2fDeviceDiscovery : public FidoDiscovery { class VirtualU2fDeviceDiscovery : public FidoDiscovery {
public: public:
VirtualU2fDeviceDiscovery()
: FidoDiscovery(U2fTransportProtocol::kUsbHumanInterfaceDevice) {}
~VirtualU2fDeviceDiscovery() override = default; ~VirtualU2fDeviceDiscovery() override = default;
U2fTransportProtocol GetTransportProtocol() const override { protected:
return U2fTransportProtocol::kUsbHumanInterfaceDevice; void StartInternal() override {
}
void Start() override {
auto device = std::make_unique<VirtualU2fDevice>(); auto device = std::make_unique<VirtualU2fDevice>();
AddDevice(std::move(device)); AddDevice(std::move(device));
NotifyDiscoveryStarted(true); base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&VirtualU2fDeviceDiscovery::NotifyDiscoveryStarted,
base::Unretained(this), true /* success */));
} }
void Stop() override { NotifyDiscoveryStopped(true); } private:
DISALLOW_COPY_AND_ASSIGN(VirtualU2fDeviceDiscovery);
}; };
ScopedVirtualU2fDevice::ScopedVirtualU2fDevice() = default; ScopedVirtualU2fDevice::ScopedVirtualU2fDevice() = default;
......
...@@ -35,15 +35,12 @@ U2fRequest::U2fRequest(service_manager::Connector* connector, ...@@ -35,15 +35,12 @@ U2fRequest::U2fRequest(service_manager::Connector* connector,
// non-HID transports are configured. // non-HID transports are configured.
continue; continue;
} }
discovery->AddObserver(this); discovery->set_observer(this);
discoveries_.push_back(std::move(discovery)); discoveries_.push_back(std::move(discovery));
} }
} }
U2fRequest::~U2fRequest() { U2fRequest::~U2fRequest() = default;
for (auto& discovery : discoveries_)
discovery->RemoveObserver(this);
}
void U2fRequest::Start() { void U2fRequest::Start() {
if (state_ == State::INIT) { if (state_ == State::INIT) {
...@@ -178,30 +175,28 @@ void U2fRequest::OnDeviceVersionRequest( ...@@ -178,30 +175,28 @@ void U2fRequest::OnDeviceVersionRequest(
} }
void U2fRequest::DiscoveryStarted(FidoDiscovery* discovery, bool success) { void U2fRequest::DiscoveryStarted(FidoDiscovery* discovery, bool success) {
#if DCHECK_IS_ON()
if (success) { if (success) {
// The discovery might know about devices that have already been added to // FidoDiscovery::Observer::DeviceAdded should have been already dispatched
// the system. Add them to the |devices_| list if we don't already know // for each of devices already known by |discovery|, so we should never
// about them. This case could happen if a DeviceAdded() event is emitted // learn anything new here.
// before DiscoveryStarted() is invoked. In that case both the U2fRequest std::set<std::string> device_ids_known_to_request;
// and the FidoDiscovery already know about the just added device.
std::set<std::string> current_device_ids;
for (const auto* device : attempted_devices_) for (const auto* device : attempted_devices_)
current_device_ids.insert(device->GetId()); device_ids_known_to_request.insert(device->GetId());
if (current_device_) if (current_device_)
current_device_ids.insert(current_device_->GetId()); device_ids_known_to_request.insert(current_device_->GetId());
for (const auto* device : devices_) for (const auto* device : devices_)
current_device_ids.insert(device->GetId()); device_ids_known_to_request.insert(device->GetId());
auto new_devices = discovery->GetDevices(); std::set<std::string> device_ids_from_newly_started_discovery;
std::copy_if( for (const auto* device : discovery->GetDevices())
new_devices.begin(), new_devices.end(), std::back_inserter(devices_), device_ids_from_newly_started_discovery.insert(device->GetId());
[&current_device_ids](FidoDevice* device) { DCHECK(base::STLIncludes(device_ids_known_to_request,
return !base::ContainsKey(current_device_ids, device->GetId()); device_ids_from_newly_started_discovery));
});
} }
#endif
started_count_++; started_count_++;
if ((state_ == State::IDLE || state_ == State::OFF) && if ((state_ == State::IDLE || state_ == State::OFF) &&
(success || started_count_ == discoveries_.size())) { (success || started_count_ == discoveries_.size())) {
state_ = State::IDLE; state_ = State::IDLE;
...@@ -209,8 +204,6 @@ void U2fRequest::DiscoveryStarted(FidoDiscovery* discovery, bool success) { ...@@ -209,8 +204,6 @@ void U2fRequest::DiscoveryStarted(FidoDiscovery* discovery, bool success) {
} }
} }
void U2fRequest::DiscoveryStopped(FidoDiscovery* discovery, bool success) {}
void U2fRequest::DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) { void U2fRequest::DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) {
devices_.push_back(device); devices_.push_back(device);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/cancelable_callback.h" #include "base/cancelable_callback.h"
#include "base/component_export.h" #include "base/component_export.h"
#include "base/containers/flat_set.h" #include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "base/optional.h"
#include "device/fido/fido_constants.h" #include "device/fido/fido_constants.h"
...@@ -114,7 +115,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) U2fRequest ...@@ -114,7 +115,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) U2fRequest
// FidoDiscovery::Observer // FidoDiscovery::Observer
void DiscoveryStarted(FidoDiscovery* discovery, bool success) override; void DiscoveryStarted(FidoDiscovery* discovery, bool success) override;
void DiscoveryStopped(FidoDiscovery* discovery, bool success) override;
void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) override; void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) override;
void DeviceRemoved(FidoDiscovery* discovery, FidoDevice* device) override; void DeviceRemoved(FidoDiscovery* discovery, FidoDevice* device) override;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment