| // |
| // Copyright (C) 2015 Google, Inc. |
| // |
| // 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: |
| // |
| // http://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 <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "service/common/bluetooth/util/address_helper.h" |
| #include "service/gatt_server.h" |
| #include "service/hal/fake_bluetooth_gatt_interface.h" |
| #include "service/hal/gatt_helpers.h" |
| |
| using ::testing::_; |
| using ::testing::Return; |
| |
| namespace bluetooth { |
| namespace { |
| |
| class MockGattHandler |
| : public hal::FakeBluetoothGattInterface::TestServerHandler { |
| public: |
| MockGattHandler() = default; |
| ~MockGattHandler() override = default; |
| |
| MOCK_METHOD1(RegisterServer, bt_status_t(bt_uuid_t*)); |
| MOCK_METHOD1(UnregisterServer, bt_status_t(int)); |
| MOCK_METHOD3(AddService, bt_status_t(int, btgatt_srvc_id_t*, int)); |
| MOCK_METHOD5(AddCharacteristic, bt_status_t(int, int, bt_uuid_t*, int, int)); |
| MOCK_METHOD4(AddDescriptor, bt_status_t(int, int, bt_uuid_t*, int)); |
| MOCK_METHOD3(StartService, bt_status_t(int, int, int)); |
| MOCK_METHOD2(DeleteService, bt_status_t(int, int)); |
| MOCK_METHOD6(SendIndication, bt_status_t(int, int, int, int, int, char*)); |
| MOCK_METHOD4(SendResponse, bt_status_t(int, int, int, btgatt_response_t*)); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MockGattHandler); |
| }; |
| |
| class TestDelegate : public GattServer::Delegate { |
| public: |
| TestDelegate() = default; |
| ~TestDelegate() override = default; |
| |
| struct RequestData { |
| RequestData() : id(-1), offset(-1), is_long(false), is_prep(false), |
| need_rsp(false), is_exec(false), count(0) {} |
| ~RequestData() = default; |
| |
| std::string device_address; |
| int id; |
| int offset; |
| bool is_long; |
| bool is_prep; |
| bool need_rsp; |
| bool is_exec; |
| GattIdentifier gatt_id; |
| int count; |
| std::vector<uint8_t> write_value; |
| }; |
| |
| void OnCharacteristicReadRequest( |
| GattServer* gatt_server, |
| const std::string& device_address, |
| int request_id, int offset, bool is_long, |
| const bluetooth::GattIdentifier& characteristic_id) override { |
| ASSERT_TRUE(gatt_server); |
| char_read_req_.device_address = device_address; |
| char_read_req_.id = request_id; |
| char_read_req_.offset = offset; |
| char_read_req_.is_long = is_long; |
| char_read_req_.gatt_id = characteristic_id; |
| char_read_req_.count++; |
| } |
| |
| void OnDescriptorReadRequest( |
| GattServer* gatt_server, |
| const std::string& device_address, |
| int request_id, int offset, bool is_long, |
| const bluetooth::GattIdentifier& descriptor_id) override { |
| ASSERT_TRUE(gatt_server); |
| desc_read_req_.device_address = device_address; |
| desc_read_req_.id = request_id; |
| desc_read_req_.offset = offset; |
| desc_read_req_.is_long = is_long; |
| desc_read_req_.gatt_id = descriptor_id; |
| desc_read_req_.count++; |
| } |
| |
| void OnCharacteristicWriteRequest( |
| GattServer* gatt_server, |
| const std::string& device_address, |
| int request_id, int offset, bool is_prepare_write, bool need_response, |
| const std::vector<uint8_t>& value, |
| const bluetooth::GattIdentifier& characteristic_id) override { |
| ASSERT_TRUE(gatt_server); |
| char_write_req_.device_address = device_address; |
| char_write_req_.id = request_id; |
| char_write_req_.offset = offset; |
| char_write_req_.is_prep = is_prepare_write; |
| char_write_req_.need_rsp = need_response; |
| char_write_req_.gatt_id = characteristic_id; |
| char_write_req_.count++; |
| char_write_req_.write_value = value; |
| } |
| |
| void OnDescriptorWriteRequest( |
| GattServer* gatt_server, |
| const std::string& device_address, |
| int request_id, int offset, bool is_prepare_write, bool need_response, |
| const std::vector<uint8_t>& value, |
| const bluetooth::GattIdentifier& descriptor_id) override { |
| ASSERT_TRUE(gatt_server); |
| desc_write_req_.device_address = device_address; |
| desc_write_req_.id = request_id; |
| desc_write_req_.offset = offset; |
| desc_write_req_.is_prep = is_prepare_write; |
| desc_write_req_.need_rsp = need_response; |
| desc_write_req_.gatt_id = descriptor_id; |
| desc_write_req_.count++; |
| desc_write_req_.write_value = value; |
| } |
| |
| void OnExecuteWriteRequest( |
| GattServer* gatt_server, |
| const std::string& device_address, |
| int request_id, bool is_execute) override { |
| ASSERT_TRUE(gatt_server); |
| exec_req_.device_address = device_address; |
| exec_req_.id = request_id; |
| exec_req_.is_exec = is_execute; |
| exec_req_.count++; |
| } |
| |
| const RequestData& char_read_req() const { return char_read_req_; } |
| const RequestData& desc_read_req() const { return desc_read_req_; } |
| const RequestData& char_write_req() const { return char_write_req_; } |
| const RequestData& desc_write_req() const { return desc_write_req_; } |
| |
| private: |
| RequestData char_read_req_; |
| RequestData desc_read_req_; |
| RequestData char_write_req_; |
| RequestData desc_write_req_; |
| RequestData exec_req_; |
| }; |
| |
| class GattServerTest : public ::testing::Test { |
| public: |
| GattServerTest() = default; |
| ~GattServerTest() override = default; |
| |
| void SetUp() override { |
| mock_handler_.reset(new MockGattHandler()); |
| fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface( |
| nullptr, |
| std::static_pointer_cast< |
| hal::FakeBluetoothGattInterface::TestServerHandler>(mock_handler_)); |
| |
| hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_); |
| factory_.reset(new GattServerFactory()); |
| } |
| |
| void TearDown() override { |
| factory_.reset(); |
| hal::BluetoothGattInterface::CleanUp(); |
| } |
| |
| protected: |
| hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_; |
| std::shared_ptr<MockGattHandler> mock_handler_; |
| std::unique_ptr<GattServerFactory> factory_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(GattServerTest); |
| }; |
| |
| const int kDefaultServerId = 4; |
| |
| class GattServerPostRegisterTest : public GattServerTest { |
| public: |
| GattServerPostRegisterTest() = default; |
| ~GattServerPostRegisterTest() override = default; |
| |
| void SetUp() override { |
| GattServerTest::SetUp(); |
| UUID uuid = UUID::GetRandom(); |
| auto callback = [&](BLEStatus status, const UUID& in_uuid, |
| std::unique_ptr<BluetoothInstance> in_client) { |
| CHECK(in_uuid == uuid); |
| CHECK(in_client.get()); |
| CHECK(status == BLE_STATUS_SUCCESS); |
| |
| gatt_server_ = std::unique_ptr<GattServer>( |
| static_cast<GattServer*>(in_client.release())); |
| }; |
| |
| EXPECT_CALL(*mock_handler_, RegisterServer(_)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| factory_->RegisterInstance(uuid, callback); |
| |
| bt_uuid_t hal_uuid = uuid.GetBlueDroid(); |
| fake_hal_gatt_iface_->NotifyRegisterServerCallback( |
| BT_STATUS_SUCCESS, |
| kDefaultServerId, |
| hal_uuid); |
| } |
| |
| void TearDown() override { |
| EXPECT_CALL(*mock_handler_, UnregisterServer(_)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| gatt_server_ = nullptr; |
| GattServerTest::TearDown(); |
| } |
| |
| void SetUpTestService() { |
| EXPECT_CALL(*mock_handler_, AddService(_, _, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| EXPECT_CALL(*mock_handler_, AddCharacteristic(_, _, _, _, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| EXPECT_CALL(*mock_handler_, AddDescriptor(_, _, _, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| EXPECT_CALL(*mock_handler_, StartService(_, _, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| UUID uuid0 = UUID::GetRandom(); |
| UUID uuid1 = UUID::GetRandom(); |
| UUID uuid2 = UUID::GetRandom(); |
| |
| bool register_success = false; |
| |
| // Doesn't matter what the permissions/properties are since this is all |
| // fake. |
| test_service_id_ = *gatt_server_->BeginServiceDeclaration(uuid0, true); |
| test_char_id_ = *gatt_server_->AddCharacteristic(uuid1, 0, 0); |
| test_desc_id_ = *gatt_server_->AddDescriptor(uuid2, 0); |
| ASSERT_TRUE(gatt_server_->EndServiceDeclaration([&]( |
| BLEStatus status, const GattIdentifier& gatt_id) { |
| ASSERT_EQ(BLE_STATUS_SUCCESS, status); |
| ASSERT_TRUE(gatt_id == test_service_id_); |
| register_success = true; |
| })); |
| |
| btgatt_srvc_id_t hal_srvc_id; |
| hal::GetHALServiceId(test_service_id_, &hal_srvc_id); |
| bt_uuid_t hal_uuid1 = uuid1.GetBlueDroid(); |
| bt_uuid_t hal_uuid2 = uuid2.GetBlueDroid(); |
| |
| srvc_handle_ = 0x0001; |
| char_handle_ = 0x0003; |
| desc_handle_ = 0x0004; |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_srvc_id, srvc_handle_); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_uuid1, |
| srvc_handle_, char_handle_); |
| fake_hal_gatt_iface_->NotifyDescriptorAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_uuid2, |
| srvc_handle_, desc_handle_); |
| fake_hal_gatt_iface_->NotifyServiceStartedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, srvc_handle_); |
| |
| testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); |
| |
| ASSERT_TRUE(register_success); |
| } |
| |
| protected: |
| std::unique_ptr<GattServer> gatt_server_; |
| |
| GattIdentifier test_service_id_; |
| GattIdentifier test_char_id_; |
| GattIdentifier test_desc_id_; |
| int srvc_handle_; |
| int char_handle_; |
| int desc_handle_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(GattServerPostRegisterTest); |
| }; |
| |
| TEST_F(GattServerTest, RegisterServer) { |
| EXPECT_CALL(*mock_handler_, RegisterServer(_)) |
| .Times(2) |
| .WillOnce(Return(BT_STATUS_FAIL)) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| // These will be asynchronously populate with a result when the callback |
| // executes. |
| BLEStatus status = BLE_STATUS_SUCCESS; |
| UUID cb_uuid; |
| std::unique_ptr<GattServer> server; |
| int callback_count = 0; |
| |
| auto callback = [&](BLEStatus in_status, const UUID& uuid, |
| std::unique_ptr<BluetoothInstance> in_server) { |
| status = in_status; |
| cb_uuid = uuid; |
| server = std::unique_ptr<GattServer>( |
| static_cast<GattServer*>(in_server.release())); |
| callback_count++; |
| }; |
| |
| UUID uuid0 = UUID::GetRandom(); |
| |
| // HAL returns failure. |
| EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback)); |
| EXPECT_EQ(0, callback_count); |
| |
| // HAL returns success. |
| EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback)); |
| EXPECT_EQ(0, callback_count); |
| |
| // Calling twice with the same UUID should fail with no additional calls into |
| // the stack. |
| EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback)); |
| |
| testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); |
| |
| // Call with a different UUID while one is pending. |
| UUID uuid1 = UUID::GetRandom(); |
| EXPECT_CALL(*mock_handler_, RegisterServer(_)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| EXPECT_TRUE(factory_->RegisterInstance(uuid1, callback)); |
| |
| // Trigger callback with an unknown UUID. This should get ignored. |
| UUID uuid2 = UUID::GetRandom(); |
| bt_uuid_t hal_uuid = uuid2.GetBlueDroid(); |
| fake_hal_gatt_iface_->NotifyRegisterServerCallback(0, 0, hal_uuid); |
| EXPECT_EQ(0, callback_count); |
| |
| // |uuid0| succeeds. |
| int server_if0 = 2; // Pick something that's not 0. |
| hal_uuid = uuid0.GetBlueDroid(); |
| fake_hal_gatt_iface_->NotifyRegisterServerCallback( |
| BT_STATUS_SUCCESS, server_if0, hal_uuid); |
| |
| EXPECT_EQ(1, callback_count); |
| ASSERT_TRUE(server.get() != nullptr); // Assert to terminate in case of error |
| EXPECT_EQ(BLE_STATUS_SUCCESS, status); |
| EXPECT_EQ(server_if0, server->GetInstanceId()); |
| EXPECT_EQ(uuid0, server->GetAppIdentifier()); |
| EXPECT_EQ(uuid0, cb_uuid); |
| |
| // The server should unregister itself when deleted. |
| EXPECT_CALL(*mock_handler_, UnregisterServer(server_if0)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| server.reset(); |
| |
| testing::Mock::VerifyAndClearExpectations(mock_handler_.get()); |
| |
| // |uuid1| fails. |
| int server_if1 = 3; |
| hal_uuid = uuid1.GetBlueDroid(); |
| fake_hal_gatt_iface_->NotifyRegisterServerCallback( |
| BT_STATUS_FAIL, server_if1, hal_uuid); |
| |
| EXPECT_EQ(2, callback_count); |
| ASSERT_TRUE(server.get() == nullptr); // Assert to terminate in case of error |
| EXPECT_EQ(BLE_STATUS_FAILURE, status); |
| EXPECT_EQ(uuid1, cb_uuid); |
| } |
| |
| TEST_F(GattServerPostRegisterTest, SimpleServiceTest) { |
| // Setup a service callback. |
| GattIdentifier cb_id; |
| BLEStatus cb_status = BLE_STATUS_SUCCESS; |
| int cb_count = 0; |
| auto callback = [&](BLEStatus in_status, const GattIdentifier& in_id) { |
| cb_id = in_id; |
| cb_status = in_status; |
| cb_count++; |
| }; |
| |
| // Service declaration not started. |
| EXPECT_FALSE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| const UUID uuid = UUID::GetRandom(); |
| auto service_id = gatt_server_->BeginServiceDeclaration(uuid, true); |
| EXPECT_TRUE(service_id != nullptr); |
| EXPECT_TRUE(service_id->IsService()); |
| |
| // Already started. |
| EXPECT_FALSE(gatt_server_->BeginServiceDeclaration(uuid, false)); |
| |
| // Callback is NULL. |
| EXPECT_FALSE( |
| gatt_server_->EndServiceDeclaration(GattServer::ResultCallback())); |
| |
| // We should get a call for a service with one handle. |
| EXPECT_CALL(*mock_handler_, AddService(gatt_server_->GetInstanceId(), _, 1)) |
| .Times(2) |
| .WillOnce(Return(BT_STATUS_FAIL)) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| // Stack returns failure. This will cause the entire service declaration to |
| // end and needs to be restarted. |
| EXPECT_FALSE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| service_id = gatt_server_->BeginServiceDeclaration(uuid, true); |
| EXPECT_TRUE(service_id != nullptr); |
| EXPECT_TRUE(service_id->IsService()); |
| |
| // Stack returns success. |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| // EndServiceDeclaration already in progress. |
| EXPECT_FALSE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| EXPECT_EQ(0, cb_count); |
| |
| btgatt_srvc_id_t hal_id; |
| hal::GetHALServiceId(*service_id, &hal_id); |
| int srvc_handle = 0x0001; |
| |
| // Report success for AddService but for wrong server. Should be ignored. |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId + 1, hal_id, srvc_handle); |
| EXPECT_EQ(0, cb_count); |
| |
| // Report success for AddService. |
| EXPECT_CALL(*mock_handler_, StartService(kDefaultServerId, srvc_handle, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(0, cb_count); |
| |
| // Report success for StartService but for wrong server. Should be ignored. |
| fake_hal_gatt_iface_->NotifyServiceStartedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId + 1, srvc_handle); |
| EXPECT_EQ(0, cb_count); |
| |
| // Report success for StartService. |
| fake_hal_gatt_iface_->NotifyServiceStartedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, srvc_handle); |
| EXPECT_EQ(1, cb_count); |
| EXPECT_EQ(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Start new service declaration with same UUID. We should get a different ID. |
| auto service_id1 = gatt_server_->BeginServiceDeclaration(uuid, true); |
| EXPECT_TRUE(service_id1 != nullptr); |
| EXPECT_TRUE(service_id1->IsService()); |
| EXPECT_TRUE(*service_id != *service_id1); |
| } |
| |
| TEST_F(GattServerPostRegisterTest, AddServiceFailures) { |
| // Setup a service callback. |
| GattIdentifier cb_id; |
| BLEStatus cb_status = BLE_STATUS_SUCCESS; |
| int cb_count = 0; |
| auto callback = [&](BLEStatus in_status, const GattIdentifier& in_id) { |
| cb_id = in_id; |
| cb_status = in_status; |
| cb_count++; |
| }; |
| |
| const UUID uuid = UUID::GetRandom(); |
| auto service_id = gatt_server_->BeginServiceDeclaration(uuid, true); |
| btgatt_srvc_id_t hal_id; |
| hal::GetHALServiceId(*service_id, &hal_id); |
| int srvc_handle = 0x0001; |
| |
| EXPECT_CALL(*mock_handler_, AddService(gatt_server_->GetInstanceId(), _, 1)) |
| .Times(3) |
| .WillRepeatedly(Return(BT_STATUS_SUCCESS)); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| // Report failure for AddService. |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_FAIL, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(1, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart. We should get the same ID back. |
| auto service_id1 = gatt_server_->BeginServiceDeclaration(uuid, true); |
| EXPECT_TRUE(*service_id1 == *service_id); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| // Report success for AddService but return failure from StartService. |
| EXPECT_CALL(*mock_handler_, StartService(gatt_server_->GetInstanceId(), 1, _)) |
| .Times(2) |
| .WillOnce(Return(BT_STATUS_FAIL)) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(2, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart. |
| service_id = gatt_server_->BeginServiceDeclaration(uuid, true); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| // Report success for AddService, return success from StartService. |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(2, cb_count); |
| |
| // Report failure for StartService. Added service data should get deleted. |
| EXPECT_CALL(*mock_handler_, |
| DeleteService(gatt_server_->GetInstanceId(), srvc_handle)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| fake_hal_gatt_iface_->NotifyServiceStartedCallback( |
| BT_STATUS_FAIL, kDefaultServerId, srvc_handle); |
| EXPECT_EQ(3, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| } |
| |
| TEST_F(GattServerPostRegisterTest, AddCharacteristic) { |
| // Just pick some values. |
| const int props = bluetooth::kCharacteristicPropertyRead | |
| bluetooth::kCharacteristicPropertyNotify; |
| const int perms = kAttributePermissionReadEncrypted; |
| const UUID char_uuid = UUID::GetRandom(); |
| bt_uuid_t hal_char_uuid = char_uuid.GetBlueDroid(); |
| |
| // Declaration not started. |
| EXPECT_EQ(nullptr, gatt_server_->AddCharacteristic(char_uuid, props, perms)); |
| |
| // Start a service declaration. |
| const UUID service_uuid = UUID::GetRandom(); |
| auto service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| EXPECT_TRUE(service_id != nullptr); |
| btgatt_srvc_id_t hal_id; |
| hal::GetHALServiceId(*service_id, &hal_id); |
| |
| // Add two characteristics with the same UUID. |
| auto char_id0 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| auto char_id1 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| |
| EXPECT_TRUE(char_id0 != nullptr); |
| EXPECT_TRUE(char_id1 != nullptr); |
| EXPECT_TRUE(char_id0 != char_id1); |
| EXPECT_TRUE(char_id0->IsCharacteristic()); |
| EXPECT_TRUE(char_id1->IsCharacteristic()); |
| EXPECT_TRUE(*char_id0->GetOwningServiceId() == *service_id); |
| EXPECT_TRUE(*char_id1->GetOwningServiceId() == *service_id); |
| |
| // Expect calls for 5 handles in total as we have 2 characteristics. |
| EXPECT_CALL(*mock_handler_, AddService(kDefaultServerId, _, 5)) |
| .WillRepeatedly(Return(BT_STATUS_SUCCESS)); |
| |
| GattIdentifier cb_id; |
| BLEStatus cb_status; |
| int cb_count = 0; |
| auto callback = [&](BLEStatus in_status, const GattIdentifier& in_id) { |
| cb_id = in_id; |
| cb_status = in_status; |
| cb_count++; |
| }; |
| |
| int srvc_handle = 0x0001; |
| int char_handle0 = 0x0002; |
| int char_handle1 = 0x0004; |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| // Cannot add any more characteristics while EndServiceDeclaration is in |
| // progress. |
| EXPECT_EQ(nullptr, gatt_server_->AddCharacteristic(char_uuid, props, perms)); |
| |
| EXPECT_CALL(*mock_handler_, AddCharacteristic(_, _, _, _, _)) |
| .Times(8) |
| .WillOnce(Return(BT_STATUS_FAIL)) // char_id0 - try 1 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // char_id0 - try 2 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // char_id0 - try 3 |
| .WillOnce(Return(BT_STATUS_FAIL)) // char_id1 - try 3 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // char_id0 - try 4 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // char_id1 - try 4 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // char_id0 - try 5 |
| .WillOnce(Return(BT_STATUS_SUCCESS)); // char_id1 - try 5 |
| |
| // First AddCharacteristic call will fail. |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(1, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart. (try 2) |
| service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| char_id0 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| char_id1 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| hal::GetHALServiceId(*service_id, &hal_id); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(1, cb_count); |
| |
| // Report failure for pending AddCharacteristic. |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_FAIL, kDefaultServerId, hal_char_uuid, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(2, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart. (try 3) |
| service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| char_id0 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| char_id1 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| hal::GetHALServiceId(*service_id, &hal_id); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(2, cb_count); |
| |
| // Report success for pending AddCharacteristic we should receive a call for |
| // the second characteristic which will fail. |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(3, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart. (try 4) |
| service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| char_id0 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| char_id1 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| hal::GetHALServiceId(*service_id, &hal_id); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(3, cb_count); |
| |
| // Report success for pending AddCharacteristic. Second characteristic call |
| // will start normally. We shouldn't receive any new callback. |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(3, cb_count); |
| |
| // Report failure for pending AddCharacteristic call for second |
| // characteristic. |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_FAIL, kDefaultServerId, hal_char_uuid, |
| srvc_handle, char_handle1); |
| EXPECT_EQ(4, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart. (try 5) |
| service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| char_id0 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| char_id1 = gatt_server_->AddCharacteristic(char_uuid, props, perms); |
| hal::GetHALServiceId(*service_id, &hal_id); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(4, cb_count); |
| |
| // Report success for pending AddCharacteristic. Second characteristic call |
| // will start normally. We shouldn't receive any new callback. |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(4, cb_count); |
| |
| // Report success for pending AddCharacteristic call for second |
| // characteristic. We shouldn't receive any new callback but we'll get a call |
| // to StartService. |
| EXPECT_CALL(*mock_handler_, StartService(kDefaultServerId, srvc_handle, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid, |
| srvc_handle, char_handle1); |
| EXPECT_EQ(4, cb_count); |
| } |
| |
| TEST_F(GattServerPostRegisterTest, AddDescriptor) { |
| // Set up some values for UUIDs, permissions, and properties. |
| const UUID service_uuid = UUID::GetRandom(); |
| const UUID char_uuid0 = UUID::GetRandom(); |
| const UUID char_uuid1 = UUID::GetRandom(); |
| const UUID desc_uuid = UUID::GetRandom(); |
| bt_uuid_t hal_char_uuid0 = char_uuid0.GetBlueDroid(); |
| bt_uuid_t hal_char_uuid1 = char_uuid1.GetBlueDroid(); |
| bt_uuid_t hal_desc_uuid = desc_uuid.GetBlueDroid(); |
| const int props = bluetooth::kCharacteristicPropertyRead | |
| bluetooth::kCharacteristicPropertyNotify; |
| const int perms = kAttributePermissionReadEncrypted; |
| |
| // Service declaration not started. |
| EXPECT_EQ(nullptr, gatt_server_->AddDescriptor(desc_uuid, perms)); |
| |
| // Start a service declaration. |
| auto service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| btgatt_srvc_id_t hal_id; |
| hal::GetHALServiceId(*service_id, &hal_id); |
| |
| // No characteristic was inserted. |
| EXPECT_EQ(nullptr, gatt_server_->AddDescriptor(desc_uuid, perms)); |
| |
| // Add two characeristics. |
| auto char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms); |
| auto char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms); |
| |
| // Add a descriptor. |
| auto desc_id = gatt_server_->AddDescriptor(desc_uuid, perms); |
| EXPECT_NE(nullptr, desc_id); |
| EXPECT_TRUE(desc_id->IsDescriptor()); |
| EXPECT_TRUE(*desc_id->GetOwningCharacteristicId() == *char_id1); |
| EXPECT_TRUE(*desc_id->GetOwningServiceId() == *service_id); |
| |
| // Add a second descriptor with the same UUID. |
| auto desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms); |
| EXPECT_NE(nullptr, desc_id1); |
| EXPECT_TRUE(*desc_id1 != *desc_id); |
| EXPECT_TRUE(desc_id1->IsDescriptor()); |
| EXPECT_TRUE(*desc_id1->GetOwningCharacteristicId() == *char_id1); |
| EXPECT_TRUE(*desc_id1->GetOwningServiceId() == *service_id); |
| |
| // Expect calls for 7 handles. |
| EXPECT_CALL(*mock_handler_, AddService(kDefaultServerId, _, 7)) |
| .WillRepeatedly(Return(BT_STATUS_SUCCESS)); |
| EXPECT_CALL(*mock_handler_, AddCharacteristic(_, _, _, _, _)) |
| .WillRepeatedly(Return(BT_STATUS_SUCCESS)); |
| |
| GattIdentifier cb_id; |
| BLEStatus cb_status; |
| int cb_count = 0; |
| auto callback = [&](BLEStatus in_status, const GattIdentifier& in_id) { |
| cb_id = in_id; |
| cb_status = in_status; |
| cb_count++; |
| }; |
| |
| int srvc_handle = 0x0001; |
| int char_handle0 = 0x0002; |
| int char_handle1 = 0x0004; |
| int desc_handle0 = 0x0005; |
| int desc_handle1 = 0x0006; |
| |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| // Cannot add any more descriptors while EndServiceDeclaration is in progress. |
| EXPECT_EQ(nullptr, gatt_server_->AddDescriptor(desc_uuid, perms)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(0, cb_count); |
| |
| EXPECT_CALL(*mock_handler_, AddDescriptor(_, _, _, _)) |
| .Times(8) |
| .WillOnce(Return(BT_STATUS_FAIL)) // desc_id0 - try 1 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id0 - try 2 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id0 - try 3 |
| .WillOnce(Return(BT_STATUS_FAIL)) // desc_id1 - try 3 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id0 - try 4 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id1 - try 4 |
| .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id0 - try 5 |
| .WillOnce(Return(BT_STATUS_SUCCESS)); // desc_id1 - try 5 |
| |
| // Notify success for both characteristics. First descriptor call will fail. |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1, |
| srvc_handle, char_handle1); |
| EXPECT_EQ(1, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart (try 2) |
| cb_count = 0; |
| service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| hal::GetHALServiceId(*service_id, &hal_id); |
| char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms); |
| char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms); |
| desc_id = gatt_server_->AddDescriptor(desc_uuid, perms); |
| ASSERT_NE(nullptr, desc_id); |
| desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms); |
| ASSERT_NE(nullptr, desc_id1); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1, |
| srvc_handle, char_handle1); |
| EXPECT_EQ(0, cb_count); |
| |
| // Notify failure for first descriptor. |
| fake_hal_gatt_iface_->NotifyDescriptorAddedCallback( |
| BT_STATUS_FAIL, kDefaultServerId, hal_desc_uuid, |
| srvc_handle, desc_handle0); |
| EXPECT_EQ(1, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart (try 3) |
| cb_count = 0; |
| service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| hal::GetHALServiceId(*service_id, &hal_id); |
| char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms); |
| char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms); |
| desc_id = gatt_server_->AddDescriptor(desc_uuid, perms); |
| ASSERT_NE(nullptr, desc_id); |
| desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms); |
| ASSERT_NE(nullptr, desc_id1); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1, |
| srvc_handle, char_handle1); |
| EXPECT_EQ(0, cb_count); |
| |
| // Notify success for first descriptor; the second descriptor will fail |
| // immediately. |
| fake_hal_gatt_iface_->NotifyDescriptorAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_desc_uuid, |
| srvc_handle, desc_handle0); |
| EXPECT_EQ(1, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart (try 4) |
| cb_count = 0; |
| service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| hal::GetHALServiceId(*service_id, &hal_id); |
| char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms); |
| char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms); |
| desc_id = gatt_server_->AddDescriptor(desc_uuid, perms); |
| ASSERT_NE(nullptr, desc_id); |
| desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms); |
| ASSERT_NE(nullptr, desc_id1); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1, |
| srvc_handle, char_handle1); |
| EXPECT_EQ(0, cb_count); |
| |
| // Notify success for first first descriptor and failure for second |
| // descriptor. |
| fake_hal_gatt_iface_->NotifyDescriptorAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_desc_uuid, |
| srvc_handle, desc_handle0); |
| EXPECT_EQ(0, cb_count); |
| |
| fake_hal_gatt_iface_->NotifyDescriptorAddedCallback( |
| BT_STATUS_FAIL, kDefaultServerId, hal_desc_uuid, |
| srvc_handle, desc_handle1); |
| EXPECT_EQ(1, cb_count); |
| EXPECT_NE(BLE_STATUS_SUCCESS, cb_status); |
| EXPECT_TRUE(cb_id == *service_id); |
| |
| // Restart (try 5) |
| cb_count = 0; |
| service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true); |
| hal::GetHALServiceId(*service_id, &hal_id); |
| char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms); |
| char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms); |
| desc_id = gatt_server_->AddDescriptor(desc_uuid, perms); |
| ASSERT_NE(nullptr, desc_id); |
| desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms); |
| ASSERT_NE(nullptr, desc_id1); |
| EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback)); |
| |
| fake_hal_gatt_iface_->NotifyServiceAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0, |
| srvc_handle, char_handle0); |
| EXPECT_EQ(0, cb_count); |
| fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1, |
| srvc_handle, char_handle1); |
| EXPECT_EQ(0, cb_count); |
| |
| // Notify success for both descriptors. |
| fake_hal_gatt_iface_->NotifyDescriptorAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_desc_uuid, |
| srvc_handle, desc_handle0); |
| EXPECT_EQ(0, cb_count); |
| |
| // The second descriptor callback should trigger the end routine. |
| EXPECT_CALL(*mock_handler_, StartService(kDefaultServerId, srvc_handle, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| fake_hal_gatt_iface_->NotifyDescriptorAddedCallback( |
| BT_STATUS_SUCCESS, kDefaultServerId, hal_desc_uuid, |
| srvc_handle, desc_handle1); |
| EXPECT_EQ(0, cb_count); |
| } |
| |
| TEST_F(GattServerPostRegisterTest, RequestRead) { |
| SetUpTestService(); |
| |
| TestDelegate test_delegate; |
| gatt_server_->SetDelegate(&test_delegate); |
| |
| const std::vector<uint8_t> kTestValue = { 0x01, 0x02, 0x03 }; |
| const std::vector<uint8_t> kTestValueTooLarge(BTGATT_MAX_ATTR_LEN + 1, 0); |
| const std::string kTestAddress0 = "01:23:45:67:89:AB"; |
| const std::string kTestAddress1 = "CD:EF:01:23:45:67"; |
| const int kReqId0 = 0; |
| const int kReqId1 = 1; |
| const int kConnId0 = 1; |
| |
| // No pending request. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| bt_bdaddr_t hal_addr0, hal_addr1; |
| ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0)); |
| ASSERT_TRUE(util::BdAddrFromString(kTestAddress1, &hal_addr1)); |
| |
| // Send a connection callback. The GattServer should store the connection |
| // information and be able to process the incoming read requests for this |
| // connection. |
| fake_hal_gatt_iface_->NotifyServerConnectionCallback( |
| kConnId0, kDefaultServerId, true, hal_addr0); |
| |
| // Unknown connection ID shouldn't trigger anything. |
| fake_hal_gatt_iface_->NotifyRequestReadCallback( |
| kConnId0 + 1, kReqId0, hal_addr0, char_handle_, 0, false); |
| EXPECT_EQ(0, test_delegate.char_read_req().count); |
| EXPECT_EQ(0, test_delegate.desc_read_req().count); |
| |
| // Unknown device address shouldn't trigger anything. |
| fake_hal_gatt_iface_->NotifyRequestReadCallback( |
| kConnId0, kReqId0, hal_addr1, char_handle_, 0, false); |
| EXPECT_EQ(0, test_delegate.char_read_req().count); |
| EXPECT_EQ(0, test_delegate.desc_read_req().count); |
| |
| // Unknown attribute handle shouldn't trigger anything. |
| fake_hal_gatt_iface_->NotifyRequestReadCallback( |
| kConnId0, kReqId0, hal_addr0, char_handle_ + 50, 0, false); |
| EXPECT_EQ(0, test_delegate.char_read_req().count); |
| EXPECT_EQ(0, test_delegate.desc_read_req().count); |
| |
| // Characteristic and descriptor handles should trigger correct callbacks. |
| fake_hal_gatt_iface_->NotifyRequestReadCallback( |
| kConnId0, kReqId0, hal_addr0, char_handle_, 0, false); |
| EXPECT_EQ(1, test_delegate.char_read_req().count); |
| EXPECT_EQ(kTestAddress0, test_delegate.char_read_req().device_address); |
| EXPECT_EQ(kReqId0, test_delegate.char_read_req().id); |
| EXPECT_EQ(0, test_delegate.char_read_req().offset); |
| EXPECT_FALSE(test_delegate.char_read_req().is_long); |
| EXPECT_TRUE(test_char_id_ == test_delegate.char_read_req().gatt_id); |
| EXPECT_EQ(0, test_delegate.desc_read_req().count); |
| |
| fake_hal_gatt_iface_->NotifyRequestReadCallback( |
| kConnId0, kReqId1, hal_addr0, desc_handle_, 2, true); |
| EXPECT_EQ(1, test_delegate.char_read_req().count); |
| EXPECT_EQ(1, test_delegate.desc_read_req().count); |
| EXPECT_EQ(kTestAddress0, test_delegate.desc_read_req().device_address); |
| EXPECT_EQ(kReqId1, test_delegate.desc_read_req().id); |
| EXPECT_EQ(2, test_delegate.desc_read_req().offset); |
| EXPECT_TRUE(test_delegate.desc_read_req().is_long); |
| EXPECT_TRUE(test_desc_id_ == test_delegate.desc_read_req().gatt_id); |
| |
| // Callback with a pending request ID will be ignored. |
| fake_hal_gatt_iface_->NotifyRequestReadCallback( |
| kConnId0, kReqId0, hal_addr0, char_handle_, 0, false); |
| fake_hal_gatt_iface_->NotifyRequestReadCallback( |
| kConnId0, kReqId1, hal_addr0, char_handle_, 0, false); |
| EXPECT_EQ(1, test_delegate.char_read_req().count); |
| EXPECT_EQ(1, test_delegate.desc_read_req().count); |
| |
| // Send response for wrong device address. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress1, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| // Send response for a value that's too large. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValueTooLarge)); |
| |
| EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId0, |
| BT_STATUS_SUCCESS, _)) |
| .Times(2) |
| .WillOnce(Return(BT_STATUS_FAIL)) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| // Stack call fails. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| // Successful send response for characteristic. |
| EXPECT_TRUE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| // Characteristic request ID no longer pending. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId1, |
| BT_STATUS_SUCCESS, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| // Successful send response for descriptor. |
| EXPECT_TRUE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId1, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| // Descriptor request ID no longer pending. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId1, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| gatt_server_->SetDelegate(nullptr); |
| } |
| |
| TEST_F(GattServerPostRegisterTest, RequestWrite) { |
| SetUpTestService(); |
| |
| TestDelegate test_delegate; |
| gatt_server_->SetDelegate(&test_delegate); |
| |
| const std::vector<uint8_t> kTestValue = { 0x01, 0x02, 0x03 }; |
| const std::string kTestAddress0 = "01:23:45:67:89:AB"; |
| const std::string kTestAddress1 = "CD:EF:01:23:45:67"; |
| const int kReqId0 = 0; |
| const int kReqId1 = 1; |
| const int kConnId0 = 1; |
| |
| // No pending request. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| bt_bdaddr_t hal_addr0, hal_addr1; |
| ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0)); |
| ASSERT_TRUE(util::BdAddrFromString(kTestAddress1, &hal_addr1)); |
| |
| // Send a connection callback. The GattServer should store the connection |
| // information and be able to process the incoming read requests for this |
| // connection. |
| fake_hal_gatt_iface_->NotifyServerConnectionCallback( |
| kConnId0, kDefaultServerId, true, hal_addr0); |
| |
| // Unknown connection ID shouldn't trigger anything. |
| fake_hal_gatt_iface_->NotifyRequestWriteCallback( |
| kConnId0 + 1, kReqId0, hal_addr0, char_handle_, 0, |
| kTestValue.size(), true, false, (uint8_t *)kTestValue.data()); |
| EXPECT_EQ(0, test_delegate.char_write_req().count); |
| EXPECT_EQ(0, test_delegate.desc_write_req().count); |
| |
| // Unknown device address shouldn't trigger anything. |
| fake_hal_gatt_iface_->NotifyRequestWriteCallback( |
| kConnId0, kReqId0, hal_addr1, char_handle_, 0, |
| kTestValue.size(), true, false, (uint8_t *)kTestValue.data()); |
| EXPECT_EQ(0, test_delegate.char_write_req().count); |
| EXPECT_EQ(0, test_delegate.desc_write_req().count); |
| |
| // Unknown attribute handle shouldn't trigger anything. |
| fake_hal_gatt_iface_->NotifyRequestWriteCallback( |
| kConnId0, kReqId0, hal_addr0, char_handle_ + 50, 0, |
| kTestValue.size(), true, false, (uint8_t *)kTestValue.data()); |
| EXPECT_EQ(0, test_delegate.char_write_req().count); |
| EXPECT_EQ(0, test_delegate.desc_write_req().count); |
| |
| // Characteristic and descriptor handles should trigger correct callbacks. |
| fake_hal_gatt_iface_->NotifyRequestWriteCallback( |
| kConnId0, kReqId0, hal_addr0, char_handle_, 0, |
| kTestValue.size(), true, false, (uint8_t *)kTestValue.data()); |
| EXPECT_EQ(1, test_delegate.char_write_req().count); |
| EXPECT_EQ(kTestAddress0, test_delegate.char_write_req().device_address); |
| EXPECT_EQ(kReqId0, test_delegate.char_write_req().id); |
| EXPECT_EQ(0, test_delegate.char_write_req().offset); |
| EXPECT_EQ(true, test_delegate.char_write_req().need_rsp); |
| EXPECT_EQ(false, test_delegate.char_write_req().is_exec); |
| EXPECT_EQ(kTestValue, test_delegate.char_write_req().write_value); |
| EXPECT_TRUE(test_char_id_ == test_delegate.char_write_req().gatt_id); |
| EXPECT_EQ(0, test_delegate.desc_write_req().count); |
| |
| fake_hal_gatt_iface_->NotifyRequestWriteCallback( |
| kConnId0, kReqId1, hal_addr0, desc_handle_, 2, |
| kTestValue.size(), true, false, (uint8_t *)kTestValue.data()); |
| EXPECT_EQ(1, test_delegate.char_write_req().count); |
| EXPECT_EQ(1, test_delegate.desc_write_req().count); |
| EXPECT_EQ(kTestAddress0, test_delegate.desc_write_req().device_address); |
| EXPECT_EQ(kReqId1, test_delegate.desc_write_req().id); |
| EXPECT_EQ(2, test_delegate.desc_write_req().offset); |
| EXPECT_EQ(true, test_delegate.desc_write_req().need_rsp); |
| EXPECT_EQ(false, test_delegate.desc_write_req().is_exec); |
| EXPECT_EQ(kTestValue, test_delegate.desc_write_req().write_value); |
| EXPECT_TRUE(test_desc_id_ == test_delegate.desc_write_req().gatt_id); |
| |
| // Callback with a pending request ID will be ignored. |
| fake_hal_gatt_iface_->NotifyRequestWriteCallback( |
| kConnId0, kReqId0, hal_addr0, char_handle_, 0, |
| kTestValue.size(), true, false, (uint8_t *)kTestValue.data()); |
| fake_hal_gatt_iface_->NotifyRequestWriteCallback( |
| kConnId0, kReqId1, hal_addr0, char_handle_, 0, |
| kTestValue.size(), true, false, (uint8_t *)kTestValue.data()); |
| EXPECT_EQ(1, test_delegate.char_write_req().count); |
| EXPECT_EQ(1, test_delegate.desc_write_req().count); |
| |
| // Send response for wrong device address. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress1, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId0, |
| BT_STATUS_SUCCESS, _)) |
| .Times(2) |
| .WillOnce(Return(BT_STATUS_FAIL)) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| // Stack call fails. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| // Successful send response for characteristic. |
| EXPECT_TRUE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| // Characteristic request ID no longer pending. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId1, |
| BT_STATUS_SUCCESS, _)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| |
| // Successful send response for descriptor. |
| EXPECT_TRUE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId1, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| // Descriptor request ID no longer pending. |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId1, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| // SendResponse should fail for a "Write Without Response". |
| fake_hal_gatt_iface_->NotifyRequestWriteCallback( |
| kConnId0, kReqId0, hal_addr0, char_handle_, 0, |
| kTestValue.size(), false, false, (uint8_t *)kTestValue.data()); |
| EXPECT_EQ(false, test_delegate.char_write_req().need_rsp); |
| EXPECT_FALSE(gatt_server_->SendResponse( |
| kTestAddress0, kReqId0, |
| GATT_ERROR_NONE, 0, kTestValue)); |
| |
| gatt_server_->SetDelegate(nullptr); |
| } |
| |
| TEST_F(GattServerPostRegisterTest, SendNotification) { |
| SetUpTestService(); |
| |
| const std::string kTestAddress0 = "01:23:45:67:89:AB"; |
| const std::string kTestAddress1 = "cd:ef:01:23:45:67"; |
| const std::string kInvalidAddress = "thingamajig blabbidyboop"; |
| const int kConnId0 = 0; |
| const int kConnId1 = 1; |
| std::vector<uint8_t> value; |
| bt_bdaddr_t hal_addr0; |
| ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0)); |
| |
| // Set up two connections with the same address. |
| fake_hal_gatt_iface_->NotifyServerConnectionCallback( |
| kConnId0, kDefaultServerId, true, hal_addr0); |
| fake_hal_gatt_iface_->NotifyServerConnectionCallback( |
| kConnId1, kDefaultServerId, true, hal_addr0); |
| |
| // Set up a test callback. |
| GATTError gatt_error; |
| int callback_count = 0; |
| auto callback = [&](GATTError in_error) { |
| gatt_error = in_error; |
| callback_count++; |
| }; |
| |
| // Bad device address. |
| EXPECT_FALSE(gatt_server_->SendNotification( |
| kInvalidAddress, |
| test_char_id_, false, value, callback)); |
| |
| // Bad connection. |
| EXPECT_FALSE(gatt_server_->SendNotification( |
| kTestAddress1, |
| test_char_id_, false, value, callback)); |
| |
| // We should get a HAL call for each connection for this address. The calls |
| // fail. |
| EXPECT_CALL(*mock_handler_, |
| SendIndication(kDefaultServerId, char_handle_, kConnId0, |
| value.size(), 0, nullptr)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_FAIL)); |
| EXPECT_CALL(*mock_handler_, |
| SendIndication(kDefaultServerId, char_handle_, kConnId1, |
| value.size(), 0, nullptr)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_FAIL)); |
| EXPECT_FALSE(gatt_server_->SendNotification( |
| kTestAddress0, |
| test_char_id_, false, value, callback)); |
| |
| // One of the calls succeeds. |
| EXPECT_CALL(*mock_handler_, |
| SendIndication(kDefaultServerId, char_handle_, kConnId0, |
| value.size(), 0, nullptr)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| EXPECT_CALL(*mock_handler_, |
| SendIndication(kDefaultServerId, char_handle_, kConnId1, |
| value.size(), 0, nullptr)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_FAIL)); |
| EXPECT_TRUE(gatt_server_->SendNotification( |
| kTestAddress0, |
| test_char_id_, false, value, callback)); |
| |
| // One of the connections is already pending so there should be only one call. |
| // This one we send with confirm=true. |
| EXPECT_CALL(*mock_handler_, |
| SendIndication(kDefaultServerId, char_handle_, kConnId1, |
| value.size(), 1, nullptr)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| EXPECT_TRUE(gatt_server_->SendNotification( |
| kTestAddress0, |
| test_char_id_, true, value, callback)); |
| |
| // Calls are already pending. |
| EXPECT_FALSE(gatt_server_->SendNotification( |
| kTestAddress0, test_char_id_, true, value, callback)); |
| |
| // Trigger one confirmation callback. We should get calls for two callbacks |
| // since we have two separate calls pending. |
| fake_hal_gatt_iface_->NotifyIndicationSentCallback( |
| kConnId0, BT_STATUS_SUCCESS); |
| fake_hal_gatt_iface_->NotifyIndicationSentCallback( |
| kConnId1, BT_STATUS_SUCCESS); |
| EXPECT_EQ(2, callback_count); |
| EXPECT_EQ(GATT_ERROR_NONE, gatt_error); |
| |
| callback_count = 0; |
| |
| // Restart. Both calls succeed now. |
| EXPECT_CALL(*mock_handler_, |
| SendIndication(kDefaultServerId, char_handle_, kConnId0, |
| value.size(), 0, nullptr)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| EXPECT_CALL(*mock_handler_, |
| SendIndication(kDefaultServerId, char_handle_, kConnId1, |
| value.size(), 0, nullptr)) |
| .Times(1) |
| .WillOnce(Return(BT_STATUS_SUCCESS)); |
| EXPECT_TRUE(gatt_server_->SendNotification( |
| kTestAddress0, |
| test_char_id_, false, value, callback)); |
| |
| // Trigger one confirmation callback. The callback we passed should still be |
| // pending. The first callback is for the wrong connection ID. |
| fake_hal_gatt_iface_->NotifyIndicationSentCallback( |
| kConnId0 + 50, BT_STATUS_FAIL); |
| fake_hal_gatt_iface_->NotifyIndicationSentCallback( |
| kConnId0, BT_STATUS_SUCCESS); |
| EXPECT_EQ(0, callback_count); |
| |
| // This should be ignored since |kConnId0| was already processed. |
| fake_hal_gatt_iface_->NotifyIndicationSentCallback( |
| kConnId0, BT_STATUS_SUCCESS); |
| EXPECT_EQ(0, callback_count); |
| |
| // Run the callback with failure. Since the previous callback reported |
| // success, we should report success. |
| fake_hal_gatt_iface_->NotifyIndicationSentCallback( |
| kConnId1, BT_STATUS_SUCCESS); |
| EXPECT_EQ(1, callback_count); |
| EXPECT_EQ(GATT_ERROR_NONE, gatt_error); |
| } |
| |
| } // namespace |
| } // namespace bluetooth |