blob: 491c37ab5f00411de4fdf7e43423af59f5df6f1c [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// clang-format off
#include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h>
#include <Weave/DeviceLayer/internal/BLEManager.h>
#include "src/connectivity/weave/adaptation/ble_manager_impl.h"
// clang-format on
#include <fuchsia/bluetooth/gatt/cpp/fidl_test_base.h>
#include <fuchsia/bluetooth/le/cpp/fidl_test_base.h>
#include <lib/gtest/test_loop_fixture.h>
#include <lib/sys/cpp/testing/component_context_provider.h>
#include <lib/syslog/cpp/macros.h>
#include <gtest/gtest.h>
#include "configuration_manager_delegate_impl.h"
#include "connectivity_manager_delegate_impl.h"
#include "thread_stack_manager_delegate_impl.h"
#include "weave_test_fixture.h"
namespace nl::Weave::DeviceLayer::Internal {
namespace testing {
namespace {
using nl::Weave::DeviceLayer::ConnectivityManager;
using nl::Weave::DeviceLayer::Internal::BLEManager;
using nl::Weave::DeviceLayer::Internal::BLEManagerImpl;
using nl::Weave::DeviceLayer::Internal::BLEMgr;
} // namespace
class FakeGATTLocalService : public fuchsia::bluetooth::gatt::testing::LocalService_TestBase {
public:
void NotImplemented_(const std::string& name) override { FAIL() << __func__; }
void RemoveService() override {
binding_.Unbind();
gatt_subscribe_confirmed_ = false;
}
void NotifyValue(uint64_t characteristic_id, std::string peer_id, std::vector<uint8_t> value,
bool confirm) override {
gatt_subscribe_confirmed_ = true;
}
fidl::Binding<fuchsia::bluetooth::gatt::LocalService> binding_{this};
bool gatt_subscribe_confirmed_{false};
};
class FakeGATTService : public fuchsia::bluetooth::gatt::testing::Server_TestBase {
public:
void NotImplemented_(const std::string& name) override { FAIL() << __func__; }
void PublishService(
fuchsia::bluetooth::gatt::ServiceInfo info,
fidl::InterfaceHandle<fuchsia::bluetooth::gatt::LocalServiceDelegate> delegate,
fidl::InterfaceRequest<fuchsia::bluetooth::gatt::LocalService> service,
PublishServiceCallback callback) override {
::fuchsia::bluetooth::Status resp;
local_service_.binding_.Bind(std::move(service), gatt_server_dispatcher_);
local_service_delegate_ = delegate.BindSync();
callback(std::move(resp));
}
fidl::InterfaceRequestHandler<fuchsia::bluetooth::gatt::Server> GetHandler(
async_dispatcher_t* dispatcher = nullptr) {
gatt_server_dispatcher_ = dispatcher;
return [this, dispatcher](fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Server> request) {
FX_LOGS(INFO) << "Binding to fake fuchsia::bluetooth::gatt::Server ";
binding_.Bind(std::move(request), dispatcher);
};
}
fuchsia::bluetooth::gatt::ErrorCode WriteRequest() {
// BTP connect request
std::vector<uint8_t> value{0x6E, 0x6C, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5};
fuchsia::bluetooth::gatt::ErrorCode out_status;
local_service_delegate_->OnWriteValue(0, 0, value, &out_status);
return out_status;
}
void OnCharacteristicConfiguration() {
local_service_delegate_->OnCharacteristicConfiguration(1, "123456", false, true);
}
bool WeaveConnectionConfirmed() { return local_service_.gatt_subscribe_confirmed_; }
private:
fidl::Binding<fuchsia::bluetooth::gatt::Server> binding_{this};
async_dispatcher_t* gatt_server_dispatcher_;
FakeGATTLocalService local_service_;
fidl::InterfaceHandle<class fuchsia::bluetooth::gatt::LocalServiceDelegate> delegate_;
fuchsia::bluetooth::gatt::LocalServiceDelegateSyncPtr local_service_delegate_;
};
class FakeBLEPeripheral : public fuchsia::bluetooth::le::testing::Peripheral_TestBase {
public:
void NotImplemented_(const std::string& name) override { FAIL() << __func__; }
void StartAdvertising(fuchsia::bluetooth::le::AdvertisingParameters parameters,
fidl::InterfaceRequest<fuchsia::bluetooth::le::AdvertisingHandle> handle,
StartAdvertisingCallback callback) override {
fuchsia::bluetooth::le::Peripheral_StartAdvertising_Response resp;
fuchsia::bluetooth::le::Peripheral_StartAdvertising_Result result;
result.set_response(std::move(resp));
adv_handle_ = std::move(handle);
FX_LOGS(INFO) << "Sending fake StartAdvertising response";
callback(std::move(result));
}
fidl::InterfaceRequestHandler<fuchsia::bluetooth::le::Peripheral> GetHandler(
async_dispatcher_t* dispatcher = nullptr) {
le_peripheral_dispatcher_ = dispatcher;
return [this, dispatcher](fidl::InterfaceRequest<fuchsia::bluetooth::le::Peripheral> request) {
FX_LOGS(INFO) << "Binding to fake fuchsia::bluetooth::le::Peripheral ";
binding_.Bind(std::move(request), dispatcher);
};
}
private:
fidl::Binding<fuchsia::bluetooth::le::Peripheral> binding_{this};
async_dispatcher_t* le_peripheral_dispatcher_;
fidl::InterfaceRequest<fuchsia::bluetooth::le::AdvertisingHandle> adv_handle_;
};
class BLEManagerTest : public WeaveTestFixture {
public:
BLEManagerTest() {
context_provider_.service_directory_provider()->AddService(
fake_gatt_server_.GetHandler(dispatcher()));
context_provider_.service_directory_provider()->AddService(
fake_ble_peripheral_.GetHandler(dispatcher()));
}
void SetUp() {
WeaveTestFixture::SetUp();
WeaveTestFixture::RunFixtureLoop();
PlatformMgrImpl().SetComponentContextForProcess(context_provider_.TakeContext());
PlatformMgrImpl().SetDispatcher(event_loop_.dispatcher());
PlatformMgrImpl().GetSystemLayer().Init(nullptr);
ThreadStackMgrImpl().SetDelegate(std::make_unique<ThreadStackManagerDelegateImpl>());
ConfigurationMgrImpl().SetDelegate(std::make_unique<ConfigurationManagerDelegateImpl>());
ConnectivityMgrImpl().SetDelegate(std::make_unique<ConnectivityManagerDelegateImpl>());
EXPECT_EQ(ConfigurationMgrImpl().IsWoBLEEnabled(), true);
ble_mgr_ = std::make_unique<BLEManagerImpl>();
InitBleMgr();
}
void TearDown() {
event_loop_.Quit();
WeaveTestFixture::StopFixtureLoop();
WeaveTestFixture::TearDown();
ThreadStackMgrImpl().SetDelegate(nullptr);
ConfigurationMgrImpl().SetDelegate(nullptr);
ConnectivityMgrImpl().SetDelegate(nullptr);
}
protected:
std::unique_ptr<BLEManagerImpl> ble_mgr_;
void InitBleMgr() {
EXPECT_EQ(ble_mgr_->_Init(), WEAVE_NO_ERROR);
event_loop_.RunUntilIdle();
EXPECT_EQ(GetBLEMgrServiceMode(), ConnectivityManager::kWoBLEServiceMode_Enabled);
if (ConfigurationMgrImpl().IsWoBLEAdvertisementEnabled()) {
EXPECT_EQ(IsBLEMgrAdvertising(), true);
} else {
EXPECT_EQ(IsBLEMgrAdvertising(), false);
}
}
BLEManager::WoBLEServiceMode GetBLEMgrServiceMode() { return ble_mgr_->_GetWoBLEServiceMode(); }
uint16_t IsBLEMgrAdvertising() { return ble_mgr_->_IsAdvertising(); }
WEAVE_ERROR GetBLEMgrDeviceName(char* device_name, size_t device_name_size) {
return ble_mgr_->_GetDeviceName(device_name, device_name_size);
}
WEAVE_ERROR SetBLEMgrDeviceName(const char* device_name) {
return ble_mgr_->_SetDeviceName(device_name);
}
void SetWoBLEAdvertising(bool enabled) {
EXPECT_EQ(ble_mgr_->_SetAdvertisingEnabled(enabled), WEAVE_NO_ERROR);
event_loop_.RunUntilIdle();
}
void WeaveConnect() {
EXPECT_EQ(fake_gatt_server_.WriteRequest(), fuchsia::bluetooth::gatt::ErrorCode::NO_ERROR);
event_loop_.RunUntilIdle();
EXPECT_EQ(fake_gatt_server_.WeaveConnectionConfirmed(), false);
fake_gatt_server_.OnCharacteristicConfiguration();
// Event loop will be idle and waiting for subscribe request(characteristic configuration)
// on timer. So we need to wait until either subscribe request is received or timeout.
event_loop_.Run(zx::time::infinite(), true /*once*/);
// Stop fixture loop before waiting for FakeGATTLocalService::NotifyValue
// on dispatcher().
WeaveTestFixture::StopFixtureLoop();
// Wait until FakeGATTLocalService::NotifyValue is called.
RunLoopUntil([&]() {
bool res = fake_gatt_server_.WeaveConnectionConfirmed();
return res;
});
// Wait for FakeGATTLocalService::NotifyValue completed. Restart fixture loop.
WeaveTestFixture::RunFixtureLoop();
bool is_confirmed = fake_gatt_server_.WeaveConnectionConfirmed();
EXPECT_EQ(is_confirmed, true);
}
private:
sys::testing::ComponentContextProvider context_provider_;
FakeGATTService fake_gatt_server_;
FakeBLEPeripheral fake_ble_peripheral_;
async::Loop event_loop_{&kAsyncLoopConfigNoAttachToCurrentThread};
};
TEST_F(BLEManagerTest, SetAndGetDeviceName) {
constexpr char kLargeDeviceName[] = "TOO_LARGE_DEVICE_NAME_FUCHSIA";
constexpr char kDeviceName[] = "FUCHSIATEST";
char read_value[kMaxDeviceNameLength + 1];
EXPECT_EQ(SetBLEMgrDeviceName(kLargeDeviceName), WEAVE_ERROR_INVALID_ARGUMENT);
EXPECT_EQ(SetBLEMgrDeviceName(kDeviceName), WEAVE_NO_ERROR);
EXPECT_EQ(GetBLEMgrDeviceName(read_value, 1), WEAVE_ERROR_BUFFER_TOO_SMALL);
EXPECT_EQ(GetBLEMgrDeviceName(read_value, sizeof(read_value)), WEAVE_NO_ERROR);
EXPECT_STREQ(kDeviceName, read_value);
}
TEST_F(BLEManagerTest, EnableAndDisableAdvertising) {
// Disable Weave service advertising
SetWoBLEAdvertising(false);
EXPECT_EQ(IsBLEMgrAdvertising(), false);
// Enable Weave service advertising
SetWoBLEAdvertising(true);
EXPECT_EQ(IsBLEMgrAdvertising(), true);
// Re-enable Weave service advertising
SetWoBLEAdvertising(true);
EXPECT_EQ(IsBLEMgrAdvertising(), true);
}
TEST_F(BLEManagerTest, TestWeaveConnect) { WeaveConnect(); }
} // namespace testing
} // namespace nl::Weave::DeviceLayer::Internal