Files
nearby/presence/implementation/scan_manager_test.cc
T
Hai Shang fe1e14a02e internal clean up.
PiperOrigin-RevId: 538009138
2023-06-05 16:17:36 -07:00

330 lines
12 KiB
C++

// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "presence/implementation/scan_manager.h"
#include <math.h>
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/time/time.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
#include "presence/implementation/advertisement_factory.h"
#include "presence/implementation/base_broadcast_request.h"
#include "presence/implementation/credential_manager_impl.h"
#include "presence/implementation/mediums/ble.h"
#include "presence/implementation/mediums/mediums.h"
namespace nearby {
namespace presence {
namespace {
using AdvertisingSession = ::nearby::api::ble_v2::BleMedium::AdvertisingSession;
using AdvertisingCallback =
::nearby::api::ble_v2::BleMedium::AdvertisingCallback;
using ::nearby::SingleThreadExecutor;
using CountDownLatch = ::nearby::CountDownLatch;
// using ::testing::UnorderedElementsAre;
using ::testing::Contains;
class ScanManagerTest : public testing::Test {
protected:
void SetUp() override { env_.Start(); }
void TearDown() override {
executor_.Shutdown();
env_.Stop();
}
std::unique_ptr<AdvertisingSession> StartAdvertisingOn(Ble& ble) {
PresenceBroadcast::BroadcastSection section = {
.identity = internal::IDENTITY_TYPE_PUBLIC,
.extended_properties = MakeDefaultExtendedProperties(),
.account_name = "Test account"};
PresenceBroadcast presence_request = {.sections = {section}};
BroadcastRequest input = {.tx_power = 30, .variant = presence_request};
absl::StatusOr<BaseBroadcastRequest> request =
BaseBroadcastRequest::Create(input);
EXPECT_OK(request);
absl::StatusOr<AdvertisementData> advertisement =
AdvertisementFactory().CreateAdvertisement(request.value());
EXPECT_OK(advertisement);
std::unique_ptr<AdvertisingSession> session = ble.StartAdvertising(
advertisement.value(), PowerMode::kLowPower,
AdvertisingCallback{.start_advertising_result = [](absl::Status) {}});
env_.Sync();
return session;
}
ScanRequest MakeDefaultScanRequest() {
std::vector<absl::variant<PresenceScanFilter, LegacyPresenceScanFilter>>
filters = {PresenceScanFilter{
.scan_type = ScanType::kPresenceScan,
.extended_properties = MakeDefaultExtendedProperties(),
}};
return {
.account_name = "Test account",
.identity_types = MakeDefaultIdentityTypes(),
.scan_filters = filters,
.use_ble = true,
.scan_type = ScanType::kPresenceScan,
.power_mode = PowerMode::kBalanced,
.scan_only_when_screen_on = true,
};
}
ScanCallback MakeDefaultScanCallback() {
return {.start_scan_cb =
[this](absl::Status status) {
if (status.ok()) {
start_latch_.CountDown();
}
},
.on_discovered_cb =
[this](PresenceDevice pd) { found_latch_.CountDown(); }};
}
std::vector<nearby::internal::IdentityType> MakeDefaultIdentityTypes() {
return {
nearby::internal::IdentityType::IDENTITY_TYPE_PUBLIC,
};
}
std::vector<DataElement> MakeDefaultExtendedProperties() {
return {DataElement(ActionBit::kPresenceManagerAction)};
}
SingleThreadExecutor executor_;
CredentialManagerImpl credential_manager_{&executor_};
nearby::MediumEnvironment& env_ = {nearby::MediumEnvironment::Instance()};
CountDownLatch start_latch_{1};
CountDownLatch found_latch_{1};
};
TEST_F(ScanManagerTest, CanStartThenStopScanning) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_, executor_);
// Set up advertiser
nearby::BluetoothAdapter server_adapter;
Ble ble2(server_adapter);
std::unique_ptr<AdvertisingSession> advertising_session =
StartAdvertisingOn(ble2);
// Start scanning
ScanSessionId scan_session =
manager.StartScan(MakeDefaultScanRequest(), MakeDefaultScanCallback());
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 1);
EXPECT_TRUE(start_latch_.Await().Ok());
EXPECT_TRUE(found_latch_.Await().Ok());
manager.StopScan(scan_session);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
}
TEST_F(ScanManagerTest, CannotStopScanTwice) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_, executor_);
ScanSessionId scan_session =
manager.StartScan(MakeDefaultScanRequest(), MakeDefaultScanCallback());
NEARBY_LOGS(INFO) << "Start scan";
EXPECT_TRUE(start_latch_.Await().Ok());
// Ensure that we have started scanning before we try to stop.
env_.Sync();
NEARBY_LOGS(INFO) << "Stop scan";
manager.StopScan(scan_session);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
NEARBY_LOGS(INFO) << "Stop scan again";
manager.StopScan(scan_session);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
}
TEST_F(ScanManagerTest, TestNoFilter) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_, executor_);
// Set up advertiser
nearby::BluetoothAdapter server_adapter;
Ble ble2(server_adapter);
std::unique_ptr<AdvertisingSession> advertising_session =
StartAdvertisingOn(ble2);
// Start scanning
ScanRequest scan_request_no_filter = MakeDefaultScanRequest();
scan_request_no_filter.scan_filters.clear();
ScanSessionId scan_session =
manager.StartScan(scan_request_no_filter, MakeDefaultScanCallback());
ASSERT_EQ(manager.ScanningCallbacksLengthForTest(), 1);
ASSERT_TRUE(mediums.GetBle().IsAvailable());
EXPECT_TRUE(start_latch_.Await().Ok());
EXPECT_TRUE(found_latch_.Await().Ok());
manager.StopScan(scan_session);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
}
TEST_F(ScanManagerTest, PresenceMetadataIsRetained) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_, executor_);
// Set up advertiser
nearby::BluetoothAdapter server_adapter;
Ble ble2(server_adapter);
std::unique_ptr<AdvertisingSession> advertising_session =
StartAdvertisingOn(ble2);
std::string address = server_adapter.GetMacAddress();
ScanCallback callback = {
.start_scan_cb =
[this](absl::Status status) {
if (status.ok()) {
start_latch_.CountDown();
}
},
.on_discovered_cb =
[this, &address](PresenceDevice pd) {
if (pd.GetMetadata().bluetooth_mac_address() == address) {
EXPECT_THAT(
pd.GetExtendedProperties(),
Contains(
DataElement(DataElement::kPublicIdentityFieldType, ""))
.Times(1));
// MakeDefaultScanRequest() used kPresenceManagerAction for
// broadcasting. Thus verify DE and action got it recorded.
EXPECT_THAT(
pd.GetExtendedProperties(),
Contains(DataElement(ActionBit::kPresenceManagerAction))
.Times(1));
EXPECT_THAT(pd.GetActions(),
Contains(PresenceAction{
(int)ActionBit::kPresenceManagerAction})
.Times(1));
found_latch_.CountDown();
}
}};
// Start scanning
ScanRequest scan_request_no_filter = MakeDefaultScanRequest();
scan_request_no_filter.scan_filters.clear();
auto scan_session =
manager.StartScan(scan_request_no_filter, std::move(callback));
ASSERT_EQ(manager.ScanningCallbacksLengthForTest(), 1);
ASSERT_TRUE(mediums.GetBle().IsAvailable());
EXPECT_TRUE(start_latch_.Await().Ok());
EXPECT_TRUE(found_latch_.Await().Ok());
manager.StopScan(scan_session);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
}
TEST_F(ScanManagerTest, StopOneSessionFromAnotherDeadlock) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_, executor_);
CountDownLatch start_latch2{1};
CountDownLatch found_latch2{1};
// Start scanning
std::vector<DataElement> extended_properties_mismatch = {
DataElement(ActionBit::kInstantTetheringAction)};
std::vector<absl::variant<PresenceScanFilter, LegacyPresenceScanFilter>>
mismatch_filters = {PresenceScanFilter{
.scan_type = ScanType::kPresenceScan,
.extended_properties = extended_properties_mismatch,
}};
ScanRequest scan_request_mismatch = {
.account_name = "Test account",
.identity_types = MakeDefaultIdentityTypes(),
.scan_filters = mismatch_filters,
.use_ble = true,
.scan_type = ScanType::kPresenceScan,
.power_mode = PowerMode::kBalanced,
.scan_only_when_screen_on = true,
};
// we use scan_request_mismatch so this session's discovery doesn't get
// triggered.
ScanSessionId scan_session =
manager.StartScan(scan_request_mismatch, MakeDefaultScanCallback());
ScanCallback scanning_callback2 = {.start_scan_cb =
[&](absl::Status status) {
if (status.ok()) {
start_latch2.CountDown();
}
},
.on_discovered_cb =
[&](PresenceDevice pd) {
NEARBY_LOGS(INFO)
<< "scansession2 found";
found_latch2.CountDown();
manager.StopScan(scan_session);
}};
ScanSessionId scan_session2 = manager.StartScan(
MakeDefaultScanRequest(), std::move(scanning_callback2));
ASSERT_EQ(manager.ScanningCallbacksLengthForTest(), 2);
// Set up advertiser
nearby::BluetoothAdapter server_adapter;
Ble ble2(server_adapter);
std::unique_ptr<AdvertisingSession> advertising_session =
StartAdvertisingOn(ble2);
EXPECT_TRUE(found_latch2.Await().Ok());
// Session was stopped before, this should not be able to stop successfully.
manager.StopScan(scan_session);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 1);
ASSERT_TRUE(mediums.GetBle().IsAvailable());
manager.StopScan(scan_session2);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
}
// Receive a BLE advertisement after StopScan. `on_discovered_cb`
// must not be called.
TEST_F(ScanManagerTest, NoDeviceFoundAfterStopScan) {
Mediums mediums;
ScanManager manager(mediums, credential_manager_, executor_);
CountDownLatch start_scan_latch{1};
nearby::BluetoothAdapter server_adapter;
Ble ble2(server_adapter);
std::atomic_bool stopped = false;
ScanSessionId scan_session = manager.StartScan(
MakeDefaultScanRequest(),
ScanCallback{.start_scan_cb =
[&start_scan_latch](absl::Status status) {
if (status.ok()) {
start_scan_latch.CountDown();
}
},
.on_discovered_cb =
[&](PresenceDevice pd) { EXPECT_FALSE(stopped); }});
start_scan_latch.Await();
manager.StopScan(scan_session);
stopped = true;
std::unique_ptr<AdvertisingSession> advertising_session =
StartAdvertisingOn(ble2);
EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0);
executor_.Shutdown();
}
} // namespace
} // namespace presence
} // namespace nearby