Get/Write/Delete account associated device from/to footprints

PiperOrigin-RevId: 546342820
This commit is contained in:
Qin Wang
2023-07-07 11:57:29 -07:00
committed by Copybara-Service
parent ca9bbd3a9c
commit 5bab62fbb1
6 changed files with 503 additions and 7 deletions
+6 -6
View File
@@ -14,6 +14,7 @@ cc_library(
visibility = ["//fastpair:__subpackages__"],
deps = [
"//fastpair/common",
"//fastpair/proto:fastpair_cc_proto",
"//internal/base:bluetooth_address",
"//internal/crypto",
"@com_google_absl//absl/functional:any_invocable",
@@ -40,13 +41,11 @@ cc_library(
"//fastpair/proto:fastpair_cc_proto",
"//fastpair/proto:proto_builder",
"//fastpair/server_access",
"//internal/base:bluetooth_address",
"//internal/crypto",
"//internal/base",
"//internal/platform:logging",
"//internal/platform:types",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
],
)
@@ -146,14 +145,15 @@ cc_test(
"-Ithird_party",
],
deps = [
":repository",
":repository_impl",
":test_support",
"//fastpair/common",
"//fastpair/proto:fastpair_cc_proto",
"//fastpair/proto:proto_builder",
"//fastpair/server_access:test_support",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/status",
"@com_google_googletest//:gtest_main",
],
)
@@ -38,10 +38,24 @@ class FakeFastPairRepository : public FastPairRepository {
void SetFakeMetadata(absl::string_view hex_model_id, proto::Device metadata);
void ClearFakeMetadata(absl::string_view hex_model_id);
// FastPairRepository::
void AddObserver(Observer* observer) override{};
void RemoveObserver(Observer* observer) override{};
void GetDeviceMetadata(absl::string_view hex_model_id,
DeviceMetadataCallback callback) override;
void GetUserSavedDevices() override{};
void WriteAccountAssociationToFootprints(
FastPairDevice& device,
OperationToFootprintsCallback callback) override{};
void DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key,
OperationToFootprintsCallback callback) override{};
private:
absl::flat_hash_map<std::string, std::unique_ptr<DeviceMetadata>> data_;
SingleThreadExecutor executor_;
@@ -18,19 +18,34 @@
#include <functional>
#include <optional>
#include <string>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/account_key.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/proto/data.proto.h"
#include "fastpair/proto/enum.proto.h"
namespace nearby {
namespace fastpair {
using DeviceMetadataCallback =
absl::AnyInvocable<void(std::optional<DeviceMetadata> device_metadata)>;
using OperationToFootprintsCallback =
absl::AnyInvocable<void(absl::Status status)>;
class FastPairRepository {
public:
class Observer {
public:
virtual ~Observer() = default;
virtual void OnGetUserSavedDevices(
const proto::OptInStatus& opt_in_status,
const std::vector<proto::FastPairDevice>& devices) = 0;
};
static FastPairRepository* Get();
// Computes and returns the SHA256 of the concatenation of the given
@@ -40,9 +55,26 @@ class FastPairRepository {
FastPairRepository();
virtual ~FastPairRepository();
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
virtual void GetDeviceMetadata(absl::string_view hex_model_id,
DeviceMetadataCallback callback) = 0;
// Gets a list of devices saved to the current user's account and the user's
// opt in status for saving future devices to their account.
virtual void GetUserSavedDevices() = 0;
// Stores the given |account_key| for a |device| on the Footprints server.
virtual void WriteAccountAssociationToFootprints(
FastPairDevice& device, OperationToFootprintsCallback callback) = 0;
// Deletes the associated data for a given |account_key|.
virtual void DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key,
OperationToFootprintsCallback callback) = 0;
protected:
static void SetInstance(FastPairRepository* instance);
};
@@ -18,18 +18,57 @@
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/proto/data.proto.h"
#include "fastpair/proto/enum.proto.h"
#include "fastpair/proto/proto_builder.h"
#include "internal/platform/logging.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
namespace {
// This forget pattern is defined in the Android codebase as FORGET_PREFIX_BYTE
// and FORGET_PREFIX_LENGTH_IN_BYTES. Currently, those values evaluate to the
// string of bytes defined below, which is used as the prefix for the sha256
// field of the device.
constexpr absl::string_view kForgetPattern = "\xf0\xf0\xf0\xf0";
// For all intents and purposes, a device that has the "Forget pattern" is no
// longer associated to the user's account, and should be treated as removed.
bool DoesDeviceHaveForgetPattern(const proto::FastPairDevice& device) {
// The device info is modified to have no account key upon removal from
// Fast Pair Saved Devices
if (device.account_key().empty() ||
device.sha256_account_key_public_address().empty()) {
return true;
}
// To match Android behavior, we check if the SHA256 of a device begins with
// the Forget pattern, defined in Android Fast Pair code. When a device is
// forgotten from Android Bluetooth Settings, the SHA256 hash is modified to
// contain this pattern.
return (device.sha256_account_key_public_address().compare(
0, kForgetPattern.length(), kForgetPattern) == 0);
}
} // namespace
FastPairRepositoryImpl::FastPairRepositoryImpl(FastPairClient* fast_pair_client)
: fast_pair_client_(fast_pair_client) {}
void FastPairRepositoryImpl::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void FastPairRepositoryImpl::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void FastPairRepositoryImpl::GetDeviceMetadata(
absl::string_view hex_model_id, DeviceMetadataCallback callback) {
NEARBY_LOGS(INFO) << __func__ << " with model id= " << hex_model_id;
@@ -58,5 +97,102 @@ void FastPairRepositoryImpl::GetDeviceMetadata(
});
}
void FastPairRepositoryImpl::WriteAccountAssociationToFootprints(
FastPairDevice& device, OperationToFootprintsCallback callback) {
proto::UserWriteDeviceRequest request;
auto* fast_pair_info = request.mutable_fast_pair_info();
BuildFastPairInfo(fast_pair_info, device);
executor_.Execute(
"Write associated device", [this, request = std::move(request),
callback = std::move(callback)]() mutable {
NEARBY_LOGS(INFO)
<< __func__
<< ": Start to write account associated device to footprints.";
absl::StatusOr<proto::UserWriteDeviceResponse> response =
fast_pair_client_->UserWriteDevice(request);
if (response.ok()) {
NEARBY_LOGS(INFO)
<< __func__ << "Got GetWriteDeviceResponse from backend.";
std::move(callback)(absl::OkStatus());
} else {
NEARBY_LOGS(WARNING)
<< __func__
<< "Failed to get GetWriteDeviceResponse from backend.";
std::move(callback)(response.status());
}
});
}
void FastPairRepositoryImpl::DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key, OperationToFootprintsCallback callback) {
std::string hex_string = absl::BytesToHexString(account_key.GetAsBytes());
absl::AsciiStrToUpper(&hex_string);
executor_.Execute(
"Delete associated device",
[this, hex_account_key = std::move(hex_string),
callback = std::move(callback)]() mutable {
NEARBY_LOGS(INFO)
<< __func__
<< ": Start to delete account associated device from footprints";
proto::UserDeleteDeviceRequest request;
request.set_hex_account_key(hex_account_key);
absl::StatusOr<proto::UserDeleteDeviceResponse> response =
fast_pair_client_->UserDeleteDevice(request);
if (response.ok()) {
if (response->success()) {
NEARBY_LOGS(INFO)
<< __func__ << "Successfully deleted associated device.";
std::move(callback)(absl::OkStatus());
} else {
NEARBY_LOGS(WARNING) << __func__ << "Failed to delete device.";
std::move(callback)(
absl::InternalError("Failed to delete device."));
}
} else {
NEARBY_LOGS(WARNING)
<< __func__
<< "Failed to get UserDeleteDeviceResponse from backend.";
std::move(callback)(response.status());
}
});
}
void FastPairRepositoryImpl::GetUserSavedDevices() {
executor_.Execute("Get associated devices", [this]() mutable {
NEARBY_LOGS(INFO) << __func__
<< ": Start to get all account associated devices.";
proto::UserReadDevicesRequest request;
absl::StatusOr<proto::UserReadDevicesResponse> response =
fast_pair_client_->UserReadDevices(request);
if (!response.ok()) {
NEARBY_LOGS(WARNING)
<< __func__ << "Failed to get UserReadDevicesResponse from backend.";
return;
}
NEARBY_LOGS(INFO) << __func__
<< "Got UserReadDevicesResponse from backend.";
proto::OptInStatus opt_in_status =
proto::OptInStatus::OPT_IN_STATUS_UNKNOWN;
std::vector<proto::FastPairDevice> saved_devices;
for (const auto& info : response->fast_pair_info()) {
if (info.has_opt_in_status()) {
opt_in_status = info.opt_in_status();
}
// We have to check that the devices in Footprints don't use the
// "forget pattern" which Android uses in some cases to mark a device
// as removed from the user's account.
if (!info.has_device() || DoesDeviceHaveForgetPattern(info.device())) {
continue;
}
saved_devices.push_back(info.device());
}
NEARBY_LOGS(INFO) << __func__ << ": Got " << saved_devices.size()
<< " saved devices.";
for (auto& observer : observers_.GetObservers()) {
observer->OnGetUserSavedDevices(opt_in_status, saved_devices);
}
});
}
} // namespace fastpair
} // namespace nearby
@@ -20,8 +20,9 @@
#include "absl/strings/string_view.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/server_access/fast_pair_client.h"
#include "fastpair/repository/fast_pair_repository.h"
#include "fastpair/server_access/fast_pair_client.h"
#include "internal/base/observer_list.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
@@ -35,15 +36,28 @@ class FastPairRepositoryImpl : public FastPairRepository {
FastPairRepositoryImpl& operator=(const FastPairRepositoryImpl&) = delete;
~FastPairRepositoryImpl() override = default;
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
void GetDeviceMetadata(absl::string_view hex_model_id,
DeviceMetadataCallback callback) override;
void GetUserSavedDevices() override;
void WriteAccountAssociationToFootprints(
FastPairDevice& device, OperationToFootprintsCallback callback) override;
void DeleteAssociatedDeviceByAccountKey(
const AccountKey& account_key,
OperationToFootprintsCallback callback) override;
private:
// A thread for running blocking tasks.
SingleThreadExecutor executor_;
FastPairClient* fast_pair_client_;
absl::flat_hash_map<std::string, std::unique_ptr<DeviceMetadata>>
metadata_cache_;
ObserverList<FastPairRepository::Observer> observers_;
};
} // namespace fastpair
} // namespace nearby
@@ -16,11 +16,17 @@
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/status/status.h"
#include "fastpair/common/device_metadata.h"
#include "fastpair/proto/data.proto.h"
#include "fastpair/proto/fast_pair_string.proto.h"
#include "fastpair/proto/proto_builder.h"
#include "fastpair/server_access/fake_fast_pair_client.h"
#include "internal/platform/count_down_latch.h"
@@ -28,8 +34,15 @@ namespace nearby {
namespace fastpair {
namespace {
constexpr absl::string_view kHexModelId = "718C17";
constexpr absl::string_view kBleAddress = "11:22:33:44:55:66";
constexpr absl::string_view kPublicAddress = "20:64:DE:40:F8:93";
constexpr absl::string_view kDisplayName = "Test Device";
constexpr absl::string_view kAccountKey = "04b85786180add47fb81a04a8ce6b0de";
constexpr absl::string_view kInitialPairingdescription =
"InitialPairingdescription";
constexpr absl::string_view kExpectedSha256Hash =
"6353c0075a35b7d81bb30a6190ab246da4b8c55a6111d387400579133c090ed8";
constexpr absl::Duration kWaitTimeout = absl::Milliseconds(200);
// A gMock matcher to match proto values. Use this matcher like:
// request/response proto, expected_proto;
@@ -41,6 +54,29 @@ MATCHER_P(
return arg.SerializeAsString() == expected_proto.SerializeAsString();
}
class FastPairRepositoryObserver : public FastPairRepository::Observer {
public:
explicit FastPairRepositoryObserver(CountDownLatch* latch) {
latch_ = latch;
opt_in_status_ = proto::OptInStatus::OPT_IN_STATUS_UNKNOWN;
devices_ = std::vector<proto::FastPairDevice>();
}
void OnGetUserSavedDevices(
const proto::OptInStatus& opt_in_status,
const std::vector<proto::FastPairDevice>& devices) override {
for (const auto& device : devices) {
devices_.push_back(device);
}
opt_in_status_ = opt_in_status;
latch_->CountDown();
}
CountDownLatch* latch_ = nullptr;
proto::OptInStatus opt_in_status_;
std::vector<proto::FastPairDevice> devices_;
};
TEST(FastPairRepositoryImplTest, MetadataDownloadSuccess) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
@@ -71,8 +107,272 @@ TEST(FastPairRepositoryImplTest, MetadataDownloadSuccess) {
latch.CountDown();
});
latch.Await();
// Verifies proto::GetObservedDeviceRequest is as expected.
proto::GetObservedDeviceRequest expected_request =
fake_fast_pair_client.get_observer_device_request();
EXPECT_EQ(expected_request.device_id(), device_id);
EXPECT_EQ(expected_request.mode(),
proto::GetObservedDeviceRequest::MODE_RELEASE);
}
TEST(FastPairRepositoryImplTest, FailedToDownloadMetadata) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
fake_fast_pair_client.SetGetObservedDeviceResponse(
absl::InternalError("No response"));
CountDownLatch latch(1);
fast_pair_repository->GetDeviceMetadata(
kHexModelId, [&](std::optional<DeviceMetadata> device_metadata) {
EXPECT_FALSE(device_metadata.has_value());
latch.CountDown();
});
latch.Await();
}
TEST(FastPairRepositoryImplTest, GetUserSavedDevicesSuccess) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
// Sets up two devices to proto::UserReadDevicesResponse.
// Adds device 1.
proto::UserReadDevicesResponse response_proto;
FastPairDevice device_1(kHexModelId, kBleAddress,
Protocol::kFastPairInitialPairing);
AccountKey account_key(absl::HexStringToBytes(kAccountKey));
device_1.SetAccountKey(account_key);
device_1.SetPublicAddress(kPublicAddress);
device_1.SetDisplayName(kDisplayName);
proto::GetObservedDeviceResponse get_observed_device_response_1;
auto* observed_device_strings_1 =
get_observed_device_response_1.mutable_strings();
observed_device_strings_1->set_initial_pairing_description(
kInitialPairingdescription);
DeviceMetadata device_metadata_1(get_observed_device_response_1);
device_1.SetMetadata(device_metadata_1);
auto* fast_pair_info_1 = response_proto.add_fast_pair_info();
BuildFastPairInfo(fast_pair_info_1, device_1);
// Adds device 2.
auto* fast_pair_info_2 = response_proto.add_fast_pair_info();
fast_pair_info_2->set_opt_in_status(
proto::OptInStatus::OPT_IN_STATUS_OPTED_IN);
fake_fast_pair_client.SetUserReadDevicesResponse(response_proto);
// Adds FastPairRepository observer.
CountDownLatch latch(1);
FastPairRepositoryObserver observer(&latch);
EXPECT_EQ(observer.devices_.size(), 0);
EXPECT_EQ(observer.opt_in_status_, proto::OptInStatus::OPT_IN_STATUS_UNKNOWN);
fast_pair_repository->AddObserver(&observer);
// Get user's saved device from footprints.
fast_pair_repository->GetUserSavedDevices();
latch.Await();
// Verifies user's saved devices are as expected.
EXPECT_EQ(observer.opt_in_status_,
proto::OptInStatus::OPT_IN_STATUS_OPTED_IN);
EXPECT_EQ(observer.devices_.size(), 1);
proto::FastPairDevice saved_device = observer.devices_.front();
EXPECT_EQ(saved_device.account_key(), account_key.GetAsBytes());
EXPECT_EQ(
absl::BytesToHexString(saved_device.sha256_account_key_public_address()),
kExpectedSha256Hash);
proto::StoredDiscoveryItem stored_discovery_item;
EXPECT_TRUE(stored_discovery_item.ParseFromString(
saved_device.discovery_item_bytes()));
EXPECT_EQ(stored_discovery_item.title(), kDisplayName);
proto::FastPairStrings fast_pair_strings =
stored_discovery_item.fast_pair_strings();
EXPECT_EQ(fast_pair_strings.initial_pairing_description(),
kInitialPairingdescription);
fast_pair_repository->RemoveObserver(&observer);
}
TEST(FastPairRepositoryImplTest, FailedToGetUserSavedDevices) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
fake_fast_pair_client.SetUserReadDevicesResponse(
absl::InternalError("No response"));
// Adds FastPairRepository observer.
CountDownLatch latch(1);
FastPairRepositoryObserver observer(&latch);
fast_pair_repository->AddObserver(&observer);
// Get user's saved device from footprints.
fast_pair_repository->GetUserSavedDevices();
EXPECT_FALSE(latch.Await(kWaitTimeout).result());
}
TEST(FastPairRepositoryImplTest, WriteAccountAssociationToFootprintsSuccess) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
// Sets up proto::UserWriteDeviceResponse.
proto::UserWriteDeviceResponse response_proto;
fake_fast_pair_client.SetUserWriteDeviceResponse(response_proto);
// Sets up device info to be saved to footprints.
FastPairDevice fast_pair_device(kHexModelId, kBleAddress,
Protocol::kFastPairInitialPairing);
AccountKey account_key(absl::HexStringToBytes(kAccountKey));
fast_pair_device.SetAccountKey(account_key);
fast_pair_device.SetPublicAddress(kPublicAddress);
fast_pair_device.SetDisplayName(kDisplayName);
proto::GetObservedDeviceResponse get_observed_device_response;
auto* observed_device_strings =
get_observed_device_response.mutable_strings();
observed_device_strings->set_initial_pairing_description(
kInitialPairingdescription);
DeviceMetadata device_metadata(get_observed_device_response);
fast_pair_device.SetMetadata(device_metadata);
CountDownLatch latch(1);
fast_pair_repository->WriteAccountAssociationToFootprints(
fast_pair_device, [&](absl::Status status) {
// Verifies successfully write device to footprints.
EXPECT_OK(status);
latch.CountDown();
});
latch.Await();
// Verifies proto::UserWriteDeviceRequest is as expected.
proto::UserWriteDeviceRequest expected_request =
fake_fast_pair_client.write_device_request();
EXPECT_TRUE(expected_request.has_fast_pair_info());
auto fast_proto_info = expected_request.fast_pair_info();
EXPECT_TRUE(fast_proto_info.has_device());
auto device = fast_proto_info.device();
EXPECT_EQ(device.account_key(), account_key.GetAsBytes());
EXPECT_EQ(absl::BytesToHexString(device.sha256_account_key_public_address()),
kExpectedSha256Hash);
proto::StoredDiscoveryItem stored_discovery_item;
EXPECT_TRUE(
stored_discovery_item.ParseFromString(device.discovery_item_bytes()));
EXPECT_EQ(stored_discovery_item.title(), kDisplayName);
proto::FastPairStrings fast_pair_strings =
stored_discovery_item.fast_pair_strings();
EXPECT_EQ(fast_pair_strings.initial_pairing_description(),
kInitialPairingdescription);
}
TEST(FastPairRepositoryImplTest, FailedToWriteAccountAssociationToFootprints) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
fake_fast_pair_client.SetUserWriteDeviceResponse(
absl::InternalError("No response"));
// Sets up device info to be saved to footprints.
FastPairDevice fast_pair_device(kHexModelId, kBleAddress,
Protocol::kFastPairInitialPairing);
AccountKey account_key(absl::HexStringToBytes(kAccountKey));
fast_pair_device.SetAccountKey(account_key);
fast_pair_device.SetPublicAddress(kPublicAddress);
fast_pair_device.SetDisplayName(kDisplayName);
proto::GetObservedDeviceResponse get_observed_device_response;
auto* observed_device_strings =
get_observed_device_response.mutable_strings();
observed_device_strings->set_initial_pairing_description(
kInitialPairingdescription);
DeviceMetadata device_metadata(get_observed_device_response);
fast_pair_device.SetMetadata(device_metadata);
CountDownLatch latch(1);
fast_pair_repository->WriteAccountAssociationToFootprints(
fast_pair_device, [&](absl::Status status) {
// Failed to write device to footprints.
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.message(), "No response");
latch.CountDown();
});
latch.Await();
}
TEST(FastPairRepositoryImplTest, DeleteAssociatedDeviceByAccountKeySuccess) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
// Sets up proto::UserDeleteDeviceResponse
proto::UserDeleteDeviceResponse response_proto;
response_proto.set_success(true);
fake_fast_pair_client.SetUserDeleteDeviceResponse(response_proto);
// AccountKey of the device that will be removed from the footprint.
AccountKey account_key(absl::HexStringToBytes(kAccountKey));
CountDownLatch latch(1);
fast_pair_repository->DeleteAssociatedDeviceByAccountKey(
account_key, [&](absl::Status status) {
// Verifies successfully delete device from the footprints.
EXPECT_OK(status);
latch.CountDown();
});
latch.Await();
// Verifies proto::UserDeleteDeviceRequest is as expected.
proto::UserDeleteDeviceRequest expected_request =
fake_fast_pair_client.delete_device_request();
std::string hex_account_key = std::string(kAccountKey);
absl::AsciiStrToUpper(&hex_account_key);
EXPECT_EQ(expected_request.hex_account_key(), hex_account_key);
}
TEST(FastPairRepositoryImplTest, FailedToDeleteAssociatedDeviceWithNoResponse) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
fake_fast_pair_client.SetUserDeleteDeviceResponse(
absl::InternalError("No response"));
// AccountKey of the device that will be removed from the footprint.
AccountKey account_key(absl::HexStringToBytes(kAccountKey));
CountDownLatch latch(1);
fast_pair_repository->DeleteAssociatedDeviceByAccountKey(
account_key, [&](absl::Status status) {
// Failed to delete device from the footprints.
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.message(), "No response");
latch.CountDown();
});
latch.Await();
}
TEST(FastPairRepositoryImplTest, FailedToDeleteAssociatedDeviceWithError) {
FakeFastPairClient fake_fast_pair_client;
auto fast_pair_repository =
std::make_unique<FastPairRepositoryImpl>(&fake_fast_pair_client);
// Sets up proto::UserDeleteDeviceResponse
proto::UserDeleteDeviceResponse response_proto;
response_proto.set_success(false);
fake_fast_pair_client.SetUserDeleteDeviceResponse(response_proto);
// AccountKey of the device that will be removed from the footprint.
AccountKey account_key(absl::HexStringToBytes(kAccountKey));
CountDownLatch latch(1);
fast_pair_repository->DeleteAssociatedDeviceByAccountKey(
account_key, [&](absl::Status status) {
// Failed to delete device from the footprints.
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.message(), "Failed to delete device.");
latch.CountDown();
});
latch.Await();
}
} // namespace
} // namespace fastpair
} // namespace nearby