Subscribe for public credentials update

Nearby Presence scanning sessions may be very long. We need a way to notify the scanner that new credentials were added during scanning.
`SubscribeForPublicCredentials()` allows us to subscribe for such updates.

PiperOrigin-RevId: 502699345
This commit is contained in:
Janusz Sobczak
2023-01-17 15:07:14 -08:00
committed by Copybara-Service
parent 79834a0ee0
commit ca547df4d7
9 changed files with 495 additions and 81 deletions
@@ -43,6 +43,17 @@ struct CredentialSelector {
credential_selector.account_name,
static_cast<int>(credential_selector.identity_type));
}
template <typename H>
friend H AbslHashValue(H h, const CredentialSelector& selector) {
return H::combine(std::move(h), selector.manager_app_id,
selector.account_name, selector.identity_type);
}
friend bool operator==(const CredentialSelector& a,
const CredentialSelector& b) {
return a.manager_app_id == b.manager_app_id &&
a.account_name == b.account_name &&
a.identity_type == b.identity_type;
}
};
enum class PublicCredentialType {
+2
View File
@@ -75,6 +75,7 @@ cc_library(
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/hash",
"@com_google_absl//absl/log:die_if_null",
"@com_google_absl//absl/random",
"@com_google_absl//absl/random:distributions",
@@ -247,6 +248,7 @@ cc_test(
deps = [
":internal",
"//internal/platform:comm",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
@@ -98,8 +98,8 @@ class BroadcastManagerTest : public testing::TestWithParam<FeatureFlags> {
start_broadcast_status_.Set(status);
}};
Mediums mediums_;
CredentialManagerImpl credential_manager_;
nearby::SingleThreadExecutor executor_;
SingleThreadExecutor executor_;
CredentialManagerImpl credential_manager_{&executor_};
BroadcastManager broadcast_manager_{mediums_, credential_manager_, executor_};
};
@@ -27,6 +27,8 @@
namespace nearby {
namespace presence {
using SubscriberId = uint64_t;
/*
* The instance of CredentialManager is owned by {@code ServiceControllerImpl}.
* Helping service controller to manage local credentials and coordinate with
@@ -68,6 +70,20 @@ class CredentialManager {
PublicCredentialType public_credential_type,
GetPublicCredentialsResultCallback callback) = 0;
// Subscribes for public credentials updates. The `callback` is triggered when
// the public credentials are fetched initially, and then every time the
// credentials change.
virtual SubscriberId SubscribeForPublicCredentials(
const CredentialSelector& credential_selector,
PublicCredentialType public_credential_type,
GetPublicCredentialsResultCallback callback) = 0;
// Unsubscribes from public credentials updates. No new callbacks will be
// triggered after this function returns. If there is a callback already
// running, that callback may continue after
// `UnsubscribeFromPublicCredentials()` return.
virtual void UnsubscribeFromPublicCredentials(SubscriberId id) = 0;
// Decrypts the device metadata from a public credential.
// Returns an empty string if decryption fails.
virtual std::string DecryptDeviceMetadata(
@@ -14,6 +14,7 @@
#include "presence/implementation/credential_manager_impl.h"
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
@@ -25,6 +26,7 @@
#include "internal/crypto/aead.h"
#include "internal/crypto/ec_private_key.h"
#include "internal/crypto/hkdf.h"
#include "internal/crypto/random.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/future.h"
#include "internal/platform/implementation/credential_callbacks.h"
@@ -87,16 +89,27 @@ void CredentialManagerImpl::GenerateCredentials(
public_credentials, PublicCredentialType::kLocalPublicCredential,
SaveCredentialsResultCallback{
.credentials_saved_cb =
[callback = std::move(credentials_generated_cb),
[this, manager_app_id = std::string(manager_app_id),
account_name = device_metadata.account_name(),
callback = std::move(credentials_generated_cb),
public_credentials](absl::Status status) mutable {
if (status.ok()) {
std::move(callback.credentials_generated_cb)(
std::move(public_credentials));
} else {
if (!status.ok()) {
NEARBY_LOGS(WARNING)
<< "Save credentials failed with: " << status;
std::move(callback.credentials_generated_cb)(status);
return;
}
std::move(callback.credentials_generated_cb)(
std::move(public_credentials));
RunOnServiceControllerThread(
"local-creds-changed",
[this, manager_app_id = std::string(manager_app_id),
account_name = std::string(account_name)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnCredentialsChanged(
manager_app_id, account_name,
PublicCredentialType::kLocalPublicCredential);
});
}});
}
@@ -108,15 +121,27 @@ void CredentialManagerImpl::UpdateRemotePublicCredentials(
manager_app_id, account_name, /* private_credentials */ {},
remote_public_creds, PublicCredentialType::kRemotePublicCredential,
SaveCredentialsResultCallback{
.credentials_saved_cb = [callback =
std::move(credentials_updated_cb)](
absl::Status status) mutable {
if (!status.ok()) {
NEARBY_LOGS(WARNING)
<< "Update remote credentials failed with: " << status;
}
std::move(callback.credentials_updated_cb)(status);
}});
.credentials_saved_cb =
[this, manager_app_id = std::string(manager_app_id),
account_name = std::string(account_name),
callback = std::move(credentials_updated_cb)](
absl::Status status) mutable {
if (!status.ok()) {
NEARBY_LOGS(WARNING)
<< "Update remote credentials failed with: " << status;
} else {
RunOnServiceControllerThread(
"remote-creds-changed",
[this, manager_app_id = std::string(manager_app_id),
account_name = std::string(account_name)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnCredentialsChanged(
manager_app_id, account_name,
PublicCredentialType::kRemotePublicCredential);
});
}
std::move(callback.credentials_updated_cb)(status);
}});
}
std::pair<PrivateCredential, PublicCredential>
@@ -316,5 +341,131 @@ CredentialManagerImpl::GetPublicCredentialsSync(
return result.Get(timeout);
}
SubscriberId CredentialManagerImpl::SubscribeForPublicCredentials(
const CredentialSelector& credential_selector,
PublicCredentialType public_credential_type,
GetPublicCredentialsResultCallback callback) {
SubscriberId id = ::crypto::RandData<SubscriberId>();
RunOnServiceControllerThread(
"add-subscriber",
[this, key = SubscriberKey{credential_selector, public_credential_type},
id, callback = std::move(callback)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable {
AddSubscriber(key, id, std::move(callback));
});
GetPublicCredentials(credential_selector, public_credential_type,
CreateNotifySubscribersCallback(
{credential_selector, public_credential_type}));
return id;
}
void CredentialManagerImpl::UnsubscribeFromPublicCredentials(SubscriberId id) {
RunOnServiceControllerThread("remove-subscriber",
[this, id]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(
*executor_) { RemoveSubscriber(id); });
}
void CredentialManagerImpl::AddSubscriber(
SubscriberKey key, SubscriberId id,
GetPublicCredentialsResultCallback callback) {
subscribers_[key].push_back(Subscriber(id, std::move(callback)));
}
void CredentialManagerImpl::RemoveSubscriber(SubscriberId id) {
for (auto& entry : subscribers_) {
auto it = std::find_if(
entry.second.begin(), entry.second.end(),
[&](Subscriber& subscriber) { return subscriber.GetId() == id; });
if (it != entry.second.end()) {
entry.second.erase(it);
if (subscribers_[entry.first].empty()) {
subscribers_.erase(entry.first);
}
return;
}
}
}
absl::flat_hash_set<IdentityType>
CredentialManagerImpl::GetSubscribedIdentities(
absl::string_view manager_app_id, absl::string_view account_name,
PublicCredentialType credential_type) const {
absl::flat_hash_set<IdentityType> identities;
for (auto& entry : subscribers_) {
const SubscriberKey& key = entry.first;
if (key.public_credential_type == credential_type &&
key.credential_selector.manager_app_id == manager_app_id &&
key.credential_selector.account_name == account_name) {
identities.insert(key.credential_selector.identity_type);
}
}
return identities;
}
void CredentialManagerImpl::OnCredentialsChanged(
absl::string_view manager_app_id, absl::string_view account_name,
PublicCredentialType credential_type) {
NEARBY_LOGS(INFO) << "OnCredentialsChanged for app " << manager_app_id
<< ", account " << account_name;
for (IdentityType identity_type :
GetSubscribedIdentities(manager_app_id, account_name, credential_type)) {
CredentialSelector credential_selector = {
.manager_app_id = std::string(manager_app_id),
.account_name = std::string(account_name),
.identity_type = identity_type};
GetPublicCredentials(credential_selector, credential_type,
CreateNotifySubscribersCallback(
{credential_selector, credential_type}));
}
}
GetPublicCredentialsResultCallback
CredentialManagerImpl::CreateNotifySubscribersCallback(SubscriberKey key) {
return GetPublicCredentialsResultCallback{
.credentials_fetched_cb =
[this, key](
absl::StatusOr<std::vector<::nearby::internal::PublicCredential>>
credentials) {
if (!credentials.ok()) {
NEARBY_LOGS(WARNING)
<< "Failed to get public credentials: error code: "
<< credentials.status();
return;
}
RunOnServiceControllerThread(
"notify-subscribers",
[this, key, credentials = std::move(*credentials)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
NotifySubscribers(key, credentials);
});
}};
}
void CredentialManagerImpl::NotifySubscribers(
const SubscriberKey& key,
std::vector<::nearby::internal::PublicCredential> credentials) {
// We are on `executor_` thread, so we can iterate over `subscribers_`
// without locking.
auto it = subscribers_.find(key);
if (it == subscribers_.end()) {
NEARBY_LOGS(WARNING)
<< "No subscribers for (app: " << key.credential_selector.manager_app_id
<< ", account: " << key.credential_selector.account_name
<< ", identity type: "
<< static_cast<int>(key.credential_selector.identity_type)
<< ", credential type: " << static_cast<int>(key.public_credential_type)
<< ")";
return;
}
for (auto& subscriber : it->second) {
subscriber.NotifyCredentialsFetched(credentials);
}
}
void CredentialManagerImpl::Subscriber::NotifyCredentialsFetched(
std::vector<::nearby::internal::PublicCredential>& credentials) {
callback_.credentials_fetched_cb(credentials);
}
} // namespace presence
} // namespace nearby
@@ -15,16 +15,21 @@
#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_IMPL_H_
#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_IMPL_H_
#include <atomic>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "internal/platform/credential_storage_impl.h"
#include "internal/platform/implementation/credential_callbacks.h"
#include "internal/platform/runnable.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/proto/credential.pb.h"
#include "presence/implementation/credential_manager.h"
@@ -33,14 +38,19 @@ namespace presence {
class CredentialManagerImpl : public CredentialManager {
public:
CredentialManagerImpl() {
using IdentityType = ::nearby::internal::IdentityType;
explicit CredentialManagerImpl(SingleThreadExecutor* executor)
: executor_(ABSL_DIE_IF_NULL(executor)) {
credential_storage_ptr_ = std::make_unique<nearby::CredentialStorageImpl>();
}
// Test purpose only.
explicit CredentialManagerImpl(
CredentialManagerImpl(
SingleThreadExecutor* executor,
std::unique_ptr<nearby::CredentialStorageImpl> credential_storage_ptr)
: credential_storage_ptr_(std::move(credential_storage_ptr)) {}
: executor_(ABSL_DIE_IF_NULL(executor)),
credential_storage_ptr_(std::move(credential_storage_ptr)) {}
// AES only supports key sizes of 16, 24 or 32 bytes.
static constexpr int kAuthenticityKeyByteSize = 16;
@@ -85,6 +95,13 @@ class CredentialManagerImpl : public CredentialManager {
PublicCredentialType public_credential_type,
absl::Duration timeout);
SubscriberId SubscribeForPublicCredentials(
const CredentialSelector& credential_selector,
PublicCredentialType public_credential_type,
GetPublicCredentialsResultCallback callback) override;
void UnsubscribeFromPublicCredentials(SubscriberId id) override;
std::string DecryptDeviceMetadata(
absl::string_view device_metadata_encryption_key,
absl::string_view authenticity_key,
@@ -94,8 +111,7 @@ class CredentialManagerImpl : public CredentialManager {
nearby::internal::PublicCredential>
CreatePrivateCredential(
const nearby::internal::DeviceMetadata& device_metadata,
nearby::internal::IdentityType identity_type, uint64_t start_time_ms,
uint64_t end_time_ms);
IdentityType identity_type, uint64_t start_time_ms, uint64_t end_time_ms);
nearby::internal::PublicCredential CreatePublicCredential(
const nearby::internal::PrivateCredential& private_credential,
@@ -111,6 +127,62 @@ class CredentialManagerImpl : public CredentialManager {
absl::string_view device_metadata_encryption_key);
private:
struct SubscriberKey {
CredentialSelector credential_selector;
PublicCredentialType public_credential_type;
template <typename H>
friend H AbslHashValue(H h, const SubscriberKey& key) {
return H::combine(std::move(h), key.credential_selector,
key.public_credential_type);
}
friend bool operator==(const SubscriberKey& a, const SubscriberKey& b) {
return a.public_credential_type == b.public_credential_type &&
a.credential_selector == b.credential_selector;
}
};
class Subscriber {
public:
Subscriber(SubscriberId id, GetPublicCredentialsResultCallback callback)
: callback_(std::move(callback)), id_(id) {}
SubscriberId GetId() const { return id_; }
// Notifies the subscriber about fetched credentials.
void NotifyCredentialsFetched(
std::vector<::nearby::internal::PublicCredential>& credentials);
private:
GetPublicCredentialsResultCallback callback_;
SubscriberId id_;
};
void RunOnServiceControllerThread(absl::string_view name,
Runnable&& runnable) {
executor_->Execute(std::string(name), std::move(runnable));
}
void OnCredentialsChanged(absl::string_view manager_app_id,
absl::string_view account_name,
PublicCredentialType credential_type)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void NotifySubscribers(
const SubscriberKey& key,
std::vector<::nearby::internal::PublicCredential> credentials)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void AddSubscriber(SubscriberKey key, SubscriberId id,
GetPublicCredentialsResultCallback callback)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void RemoveSubscriber(SubscriberId id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
absl::flat_hash_set<IdentityType> GetSubscribedIdentities(
absl::string_view manager_app_id, absl::string_view account_name,
PublicCredentialType credential_type) const
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
GetPublicCredentialsResultCallback CreateNotifySubscribersCallback(
SubscriberKey key);
absl::flat_hash_map<SubscriberKey, std::vector<Subscriber>> subscribers_
ABSL_GUARDED_BY(*executor_);
SingleThreadExecutor* executor_;
std::unique_ptr<nearby::CredentialStorageImpl> credential_storage_ptr_;
};
@@ -27,12 +27,17 @@
#include "internal/platform/count_down_latch.h"
#include "internal/platform/credential_storage_impl.h"
#include "internal/platform/implementation/crypto.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
#include "internal/proto/credential.pb.h"
#include "internal/proto/credential.proto.h"
namespace nearby {
namespace presence {
namespace {
using ::nearby::CountDownLatch;
using ::nearby::Crypto;
using ::nearby::MediumEnvironment;
using ::nearby::internal::DeviceMetadata;
using ::nearby::internal::IdentityType;
using ::nearby::internal::PrivateCredential;
@@ -42,10 +47,14 @@ using ::proto2::contrib::parse_proto::ParseTestProto;
using ::protobuf_matchers::EqualsProto;
using ::testing::status::StatusIs;
DeviceMetadata CreateTestDeviceMetadata() {
constexpr absl::string_view kManagerAppId = "TEST_MANAGER_APP";
constexpr absl::string_view kAccountName = "test account";
DeviceMetadata CreateTestDeviceMetadata(
absl::string_view account_name = kAccountName) {
DeviceMetadata device_metadata;
device_metadata.set_stable_device_id("test_device_id");
device_metadata.set_account_name("test_account");
device_metadata.set_account_name(account_name);
device_metadata.set_device_name("NP test device");
device_metadata.set_icon_url("test_image.test.com");
device_metadata.set_bluetooth_mac_address("FF:FF:FF:FF:FF:FF");
@@ -55,8 +64,8 @@ DeviceMetadata CreateTestDeviceMetadata() {
CredentialSelector BuildDefaultCredentialSelector() {
CredentialSelector credential_selector;
credential_selector.manager_app_id = "TEST_MANAGER_APP";
credential_selector.account_name = "test_account";
credential_selector.manager_app_id = std::string(kManagerAppId);
credential_selector.account_name = std::string(kAccountName);
credential_selector.identity_type = IDENTITY_TYPE_PRIVATE;
return credential_selector;
}
@@ -85,6 +94,8 @@ class CredentialManagerImplTest : public ::testing::Test {
class MockCredentialManager : public CredentialManagerImpl {
public:
explicit MockCredentialManager(SingleThreadExecutor* executor)
: CredentialManagerImpl(executor) {}
MOCK_METHOD(std::string, EncryptDeviceMetadata,
(absl::string_view device_metadata_encryption_key,
absl::string_view authenticity_key,
@@ -92,21 +103,45 @@ class CredentialManagerImplTest : public ::testing::Test {
(override));
};
CredentialManagerImplTest() {
mock_credential_storage_ptr_ = std::make_unique<MockCredentialStorage>();
mock_credential_manager_ptr_ = std::make_unique<MockCredentialManager>();
~CredentialManagerImplTest() override { executor_.Shutdown(); }
// Waits for active tasks in the background thread to complete.
void Fence() {
// A runnable on medium environment thread can add a task on "our" executor,
// and vice-versa. We need to wait for tasks on both threads in a loop a few
// times to make sure that all tasks have finished.
for (int i = 0; i < 3; i++) {
MediumEnvironment::Instance().Sync();
CountDownLatch latch(1);
executor_.Execute([&]() { latch.CountDown(); });
latch.Await();
}
}
void AddLocalIdentity(absl::string_view manager_app_id,
absl::string_view account_name,
IdentityType identity_type) {
DeviceMetadata device_metadata = CreateTestDeviceMetadata(account_name);
credential_manager_.GenerateCredentials(
device_metadata, manager_app_id, {identity_type},
/*credential_life_cycle_days=*/1,
/*contigous_copy_of_credentials=*/1,
{[](absl::StatusOr<std::vector<PublicCredential>> credentials) {
EXPECT_OK(credentials);
}});
}
protected:
std::unique_ptr<MockCredentialStorage> mock_credential_storage_ptr_;
std::unique_ptr<MockCredentialManager> mock_credential_manager_ptr_;
SingleThreadExecutor executor_;
CredentialManagerImpl credential_manager_{&executor_};
MockCredentialManager mock_credential_manager_{&executor_};
};
TEST(CredentialManagerImpl, CreateOneCredentialSuccessfully) {
TEST_F(CredentialManagerImplTest, CreateOneCredentialSuccessfully) {
DeviceMetadata device_metadata = CreateTestDeviceMetadata();
CredentialManagerImpl credential_manager;
auto credentials = credential_manager.CreatePrivateCredential(
auto credentials = credential_manager_.CreatePrivateCredential(
device_metadata, IDENTITY_TYPE_PRIVATE, /* start_time_ms= */ 0,
/* end_time_ms= */ 1000);
@@ -141,7 +176,7 @@ TEST(CredentialManagerImpl, CreateOneCredentialSuccessfully) {
// Decrypt the device metadata
auto decrypted_device_metadata = credential_manager.DecryptDeviceMetadata(
auto decrypted_device_metadata = credential_manager_.DecryptDeviceMetadata(
private_credential.metadata_encryption_key(),
public_credential.authenticity_key(),
public_credential.encrypted_metadata_bytes());
@@ -150,16 +185,14 @@ TEST(CredentialManagerImpl, CreateOneCredentialSuccessfully) {
decrypted_device_metadata);
}
TEST(CredentialManagerImpl, GenerateCredentialsSuccessfully) {
TEST_F(CredentialManagerImplTest, GenerateCredentialsSuccessfully) {
DeviceMetadata device_metadata = CreateTestDeviceMetadata();
CredentialManagerImpl credential_manager;
absl::StatusOr<std::vector<nearby::internal::PublicCredential>>
public_credentials;
std::vector<IdentityType> identityTypes{IDENTITY_TYPE_PRIVATE};
credential_manager.GenerateCredentials(
device_metadata,
/* manager_app_id= */ "TEST_MANAGER_APP", identityTypes, 1, 2,
credential_manager_.GenerateCredentials(
device_metadata, kManagerAppId, identityTypes, 1, 2,
{.credentials_generated_cb =
[&](absl::StatusOr<std::vector<nearby::internal::PublicCredential>>
credentials) {
@@ -178,7 +211,89 @@ TEST(CredentialManagerImpl, GenerateCredentialsSuccessfully) {
}
}
TEST(CredentialManagerImpl, GenerateCredentialsSuccessfullyButStoreFailed) {
TEST_F(CredentialManagerImplTest,
SubscribeCallsCallbackWithExistingCredentials) {
absl::StatusOr<std::vector<PublicCredential>> public_credentials1;
absl::StatusOr<std::vector<PublicCredential>> public_credentials2;
AddLocalIdentity(kManagerAppId, kAccountName, IDENTITY_TYPE_PRIVATE);
SubscriberId id1 = credential_manager_.SubscribeForPublicCredentials(
CredentialSelector{.manager_app_id = std::string(kManagerAppId),
.account_name = std::string(kAccountName),
.identity_type = IDENTITY_TYPE_PRIVATE},
PublicCredentialType::kLocalPublicCredential,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PublicCredential>> credentials) {
public_credentials1 = std::move(credentials);
}});
SubscriberId id2 = credential_manager_.SubscribeForPublicCredentials(
CredentialSelector{.manager_app_id = std::string(kManagerAppId),
.account_name = std::string(kAccountName),
.identity_type = IDENTITY_TYPE_PRIVATE},
PublicCredentialType::kLocalPublicCredential,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PublicCredential>> credentials) {
public_credentials2 = std::move(credentials);
}});
Fence();
EXPECT_OK(public_credentials1);
EXPECT_OK(public_credentials2);
EXPECT_EQ(public_credentials1->size(), 1);
EXPECT_EQ(public_credentials2->size(), 1);
// Cleanup
credential_manager_.UnsubscribeFromPublicCredentials(id1);
credential_manager_.UnsubscribeFromPublicCredentials(id2);
Fence();
}
TEST_F(CredentialManagerImplTest,
SubscribeCallsCallbackWithUpdatedCredentials) {
absl::StatusOr<std::vector<PublicCredential>> public_credentials;
SubscriberId id = credential_manager_.SubscribeForPublicCredentials(
CredentialSelector{.manager_app_id = std::string(kManagerAppId),
.account_name = std::string(kAccountName),
.identity_type = IDENTITY_TYPE_PRIVATE},
PublicCredentialType::kLocalPublicCredential,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PublicCredential>> credentials) {
public_credentials = std::move(credentials);
}});
Fence();
EXPECT_THAT(public_credentials, StatusIs(absl::StatusCode::kUnknown));
AddLocalIdentity(kManagerAppId, kAccountName, IDENTITY_TYPE_PRIVATE);
Fence();
ASSERT_OK(public_credentials);
EXPECT_EQ(public_credentials->size(), 1);
// Cleanup
credential_manager_.UnsubscribeFromPublicCredentials(id);
Fence();
}
TEST_F(CredentialManagerImplTest, NoCallbacksAfterUnsubscribe) {
absl::StatusOr<std::vector<PublicCredential>> public_credentials;
SubscriberId id = credential_manager_.SubscribeForPublicCredentials(
CredentialSelector{.manager_app_id = std::string(kManagerAppId),
.account_name = std::string(kAccountName),
.identity_type = IDENTITY_TYPE_PRIVATE},
PublicCredentialType::kLocalPublicCredential,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PublicCredential>> credentials) {
public_credentials = std::move(credentials);
}});
credential_manager_.UnsubscribeFromPublicCredentials(id);
AddLocalIdentity(kManagerAppId, kAccountName, IDENTITY_TYPE_PRIVATE);
Fence();
EXPECT_THAT(public_credentials, StatusIs(absl::StatusCode::kUnknown));
}
TEST_F(CredentialManagerImplTest,
GenerateCredentialsSuccessfullyButStoreFailed) {
DeviceMetadata device_metadata = CreateTestDeviceMetadata();
auto credential_storage_ptr =
std::make_unique<CredentialManagerImplTest::MockCredentialStorage>();
@@ -192,14 +307,14 @@ TEST(CredentialManagerImpl, GenerateCredentialsSuccessfullyButStoreFailed) {
callback.credentials_saved_cb(
absl::FailedPreconditionError("Expected failure"));
}));
CredentialManagerImpl credential_manager(std::move(credential_storage_ptr));
credential_manager_ =
CredentialManagerImpl(&executor_, std::move(credential_storage_ptr));
absl::StatusOr<std::vector<nearby::internal::PublicCredential>>
public_credentials;
std::vector<IdentityType> identityTypes{IDENTITY_TYPE_PRIVATE};
credential_manager.GenerateCredentials(
device_metadata,
/* manager_app_id= */ "TEST_MANAGER_APP", identityTypes, 1, 2,
credential_manager_.GenerateCredentials(
device_metadata, kManagerAppId, identityTypes, 1, 2,
{.credentials_generated_cb =
[&](absl::StatusOr<std::vector<nearby::internal::PublicCredential>>
credentials) {
@@ -209,11 +324,11 @@ TEST(CredentialManagerImpl, GenerateCredentialsSuccessfullyButStoreFailed) {
StatusIs(absl::StatusCode::kFailedPrecondition));
}
TEST(CredentialManagerImpl, UpdateRemotePublicCredentialsSuccessfully) {
TEST_F(CredentialManagerImplTest, UpdateRemotePublicCredentialsSuccessfully) {
nearby::internal::PublicCredential public_credential_for_test;
public_credential_for_test.set_identity_type(
nearby::internal::IdentityType::IDENTITY_TYPE_TRUSTED);
std::vector<nearby::internal::PublicCredential> publicCredentials{
std::vector<nearby::internal::PublicCredential> public_credentials{
{public_credential_for_test}};
nearby::CountDownLatch updated_latch(1);
@@ -226,25 +341,68 @@ TEST(CredentialManagerImpl, UpdateRemotePublicCredentialsSuccessfully) {
},
};
CredentialManagerImpl credential_manager;
credential_manager.UpdateRemotePublicCredentials(
/* manager_app_id= */ "TEST_MANAGER_APP",
/* account_name= */ "test_account", publicCredentials,
credential_manager_.UpdateRemotePublicCredentials(
kManagerAppId, kAccountName, public_credentials,
std::move(update_credentials_cb));
EXPECT_TRUE(updated_latch.Await().Ok());
}
TEST(CredentialManagerImpl, GetPrivateCredentialsFailed) {
absl::StatusOr<std::vector<PrivateCredential>> private_credentials;
CredentialSelector credential_selector;
credential_selector.manager_app_id = "TEST_MANAGER_APP";
credential_selector.account_name = "test_account";
credential_selector.identity_type = IDENTITY_TYPE_PRIVATE;
CredentialManagerImpl credential_manager;
TEST_F(CredentialManagerImplTest,
UpdateRemotePublicCredentialsNotifiesSubscribers) {
absl::StatusOr<std::vector<PublicCredential>> subscribed_credentials;
nearby::internal::PublicCredential public_credential_for_test;
public_credential_for_test.set_identity_type(
nearby::internal::IdentityType::IDENTITY_TYPE_PRIVATE);
std::vector<nearby::internal::PublicCredential> public_credentials{
{public_credential_for_test}};
nearby::CountDownLatch updated_latch(1);
UpdateRemotePublicCredentialsCallback update_credentials_cb{
.credentials_updated_cb =
[&updated_latch](absl::Status status) {
if (status.ok()) {
updated_latch.CountDown();
}
},
};
SubscriberId id1 = credential_manager_.SubscribeForPublicCredentials(
CredentialSelector{.manager_app_id = std::string(kManagerAppId),
.account_name = std::string(kAccountName),
.identity_type = internal::IDENTITY_TYPE_PRIVATE},
PublicCredentialType::kRemotePublicCredential,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PublicCredential>> credentials) {
subscribed_credentials = std::move(credentials);
}});
SubscriberId id2 = credential_manager_.SubscribeForPublicCredentials(
CredentialSelector{.manager_app_id = std::string(kManagerAppId),
.account_name = std::string(kAccountName),
.identity_type = internal::IDENTITY_TYPE_TRUSTED},
PublicCredentialType::kRemotePublicCredential,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PublicCredential>> credentials) {
// This callback should not be called because there are no Trusted
// credentials in this test.
GTEST_FAIL();
}});
credential_manager.GetPrivateCredentials(
credential_manager_.UpdateRemotePublicCredentials(
kManagerAppId, kAccountName, public_credentials,
std::move(update_credentials_cb));
EXPECT_TRUE(updated_latch.Await().Ok());
Fence();
EXPECT_OK(subscribed_credentials);
EXPECT_EQ(subscribed_credentials->size(), 1);
credential_manager_.UnsubscribeFromPublicCredentials(id1);
credential_manager_.UnsubscribeFromPublicCredentials(id2);
}
TEST_F(CredentialManagerImplTest, GetPrivateCredentialsFailed) {
absl::StatusOr<std::vector<PrivateCredential>> private_credentials;
CredentialSelector credential_selector = BuildDefaultCredentialSelector();
credential_manager_.GetPrivateCredentials(
credential_selector,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PrivateCredential>> credentials) {
@@ -254,15 +412,11 @@ TEST(CredentialManagerImpl, GetPrivateCredentialsFailed) {
EXPECT_THAT(private_credentials, StatusIs(absl::StatusCode::kNotFound));
}
TEST(CredentialManagerImpl, GetPublicCredentialsFailed) {
TEST_F(CredentialManagerImplTest, GetPublicCredentialsFailed) {
absl::StatusOr<std::vector<PublicCredential>> public_credentials;
CredentialSelector credential_selector;
credential_selector.manager_app_id = "TEST_MANAGER_APP";
credential_selector.account_name = "test_account";
credential_selector.identity_type = IDENTITY_TYPE_PRIVATE;
CredentialManagerImpl credential_manager;
CredentialSelector credential_selector = BuildDefaultCredentialSelector();
credential_manager.GetPublicCredentials(
credential_manager_.GetPublicCredentials(
credential_selector, PublicCredentialType::kLocalPublicCredential,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PublicCredential>> credentials) {
@@ -272,23 +426,22 @@ TEST(CredentialManagerImpl, GetPublicCredentialsFailed) {
EXPECT_THAT(public_credentials, StatusIs(absl::StatusCode::kNotFound));
}
TEST(CredentialManagerImpl, GetCredentialsSuccessfully) {
TEST_F(CredentialManagerImplTest, GetCredentialsSuccessfully) {
DeviceMetadata device_metadata = CreateTestDeviceMetadata();
absl::StatusOr<std::vector<nearby::internal::PublicCredential>>
public_credentials;
CredentialManagerImpl credential_manager;
std::vector<IdentityType> identity_types{IDENTITY_TYPE_PRIVATE};
absl::StatusOr<std::vector<PrivateCredential>> private_credentials;
CredentialSelector credential_selector = BuildDefaultCredentialSelector();
credential_manager.GenerateCredentials(
device_metadata, "TEST_MANAGER_APP", identity_types, 1, 1,
credential_manager_.GenerateCredentials(
device_metadata, kManagerAppId, identity_types, 1, 1,
{.credentials_generated_cb =
[&](absl::StatusOr<std::vector<nearby::internal::PublicCredential>>
credentials) {
public_credentials = std::move(credentials);
}});
credential_manager.GetPrivateCredentials(
credential_manager_.GetPrivateCredentials(
credential_selector,
{.credentials_fetched_cb =
[&](absl::StatusOr<std::vector<PrivateCredential>> credentials) {
@@ -301,12 +454,13 @@ TEST(CredentialManagerImpl, GetCredentialsSuccessfully) {
EXPECT_FALSE(private_credentials->empty());
}
TEST(CredentialManagerImpl, PublicCredentialsFailEncryption) {
TEST_F(CredentialManagerImplTest, PublicCredentialsFailEncryption) {
DeviceMetadata device_metadata = CreateTestDeviceMetadata();
absl::StatusOr<std::vector<nearby::internal::PublicCredential>>
public_credentials;
auto credential_manager_ptr =
std::make_unique<CredentialManagerImplTest::MockCredentialManager>();
std::make_unique<CredentialManagerImplTest::MockCredentialManager>(
&executor_);
EXPECT_CALL(*credential_manager_ptr, EncryptDeviceMetadata)
.WillOnce(::testing::Invoke(
[](absl::string_view device_metadata_encryption_key,
@@ -315,7 +469,7 @@ TEST(CredentialManagerImpl, PublicCredentialsFailEncryption) {
std::vector<IdentityType> identity_types{IDENTITY_TYPE_PRIVATE};
credential_manager_ptr->GenerateCredentials(
device_metadata, "TEST_MANAGER_APP", identity_types, 1, 1,
device_metadata, kManagerAppId, identity_types, 1, 1,
{.credentials_generated_cb =
[&](absl::StatusOr<std::vector<nearby::internal::PublicCredential>>
credentials) {
+6 -3
View File
@@ -51,7 +51,10 @@ using CountDownLatch = ::nearby::CountDownLatch;
class ScanManagerTest : public testing::Test {
protected:
void SetUp() override { env_.Start(); }
void TearDown() override { env_.Stop(); }
void TearDown() override {
executor_.Shutdown();
env_.Stop();
}
std::unique_ptr<AdvertisingSession> StartAdvertisingOn(Ble& ble) {
PresenceBroadcast::BroadcastSection section = {
@@ -109,11 +112,11 @@ class ScanManagerTest : public testing::Test {
std::vector<DataElement> MakeDefaultExtendedProperties() {
return {DataElement(ActionBit::kPresenceManagerAction)};
}
CredentialManagerImpl credential_manager_;
SingleThreadExecutor executor_;
CredentialManagerImpl credential_manager_{&executor_};
nearby::MediumEnvironment& env_ = {nearby::MediumEnvironment::Instance()};
CountDownLatch start_latch_{1};
CountDownLatch found_latch_{1};
SingleThreadExecutor executor_;
};
TEST_F(ScanManagerTest, CanStartThenStopScanning) {
@@ -38,7 +38,6 @@ class ServiceControllerImpl : public ServiceController {
public:
using SingleThreadExecutor = ::nearby::SingleThreadExecutor;
ServiceControllerImpl() = default;
~ServiceControllerImpl() override { executor_.Shutdown(); }
absl::StatusOr<ScanSessionId> StartScan(ScanRequest scan_request,
@@ -55,9 +54,15 @@ class ServiceControllerImpl : public ServiceController {
private:
SingleThreadExecutor executor_;
Mediums mediums_;
CredentialManagerImpl credential_manager_;
ScanManager scan_manager_{mediums_, credential_manager_, executor_};
void NotifyStartCallbackStatus(BroadcastSessionId id, absl::Status status);
void RunOnServiceControllerThread(absl::string_view name, Runnable runnable) {
executor_.Execute(std::string(name), std::move(runnable));
}
Mediums mediums_; // NOLINT: further impl will use it.
CredentialManagerImpl credential_manager_{
&executor_}; // NOLINT: further impl will use it.
ScanManager scan_manager_{mediums_, credential_manager_,
executor_}; // NOLINT: further impl will use it.
BroadcastManager broadcast_manager_{mediums_, credential_manager_, executor_};
};