mirror of
https://github.com/google/bumble.git
synced 2026-04-16 00:25:31 +00:00
144 lines
5.1 KiB
Python
144 lines
5.1 KiB
Python
# Copyright 2021-2025 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.
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Imports
|
|
# -----------------------------------------------------------------------------
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from bumble import device, gatt
|
|
from bumble.profiles import gatt_service
|
|
|
|
from . import test_utils
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@pytest.mark.asyncio
|
|
async def test_database_hash():
|
|
devices = await test_utils.TwoDevices.create_with_connection()
|
|
devices[0].gatt_server.services.clear()
|
|
devices[0].gatt_server.attributes.clear()
|
|
devices[0].gatt_server.attributes_by_handle.clear()
|
|
devices[0].add_service(
|
|
gatt.Service(
|
|
gatt.GATT_GENERIC_ACCESS_SERVICE,
|
|
characteristics=[
|
|
gatt.Characteristic(
|
|
gatt.GATT_DEVICE_NAME_CHARACTERISTIC,
|
|
(
|
|
gatt.Characteristic.Properties.READ
|
|
| gatt.Characteristic.Properties.WRITE
|
|
),
|
|
gatt.Characteristic.Permissions.READ_REQUIRES_AUTHENTICATION,
|
|
),
|
|
gatt.Characteristic(
|
|
gatt.GATT_APPEARANCE_CHARACTERISTIC,
|
|
gatt.Characteristic.Properties.READ,
|
|
gatt.Characteristic.Permissions.READ_REQUIRES_AUTHENTICATION,
|
|
),
|
|
],
|
|
)
|
|
)
|
|
devices[0].add_service(
|
|
gatt_service.GenericAttributeProfileService(
|
|
server_supported_features=None,
|
|
database_hash_enabled=True,
|
|
service_change_enabled=True,
|
|
)
|
|
)
|
|
devices[0].gatt_server.add_attribute(
|
|
gatt.Service(gatt.GATT_GLUCOSE_SERVICE, characteristics=[])
|
|
)
|
|
# There is a special attribute order in the spec, so we need to add attribute one by
|
|
# one here.
|
|
battery_service = gatt.Service(
|
|
gatt.GATT_BATTERY_SERVICE,
|
|
characteristics=[
|
|
gatt.Characteristic(
|
|
gatt.GATT_BATTERY_LEVEL_CHARACTERISTIC,
|
|
properties=gatt.Characteristic.Properties.READ,
|
|
permissions=gatt.Characteristic.Permissions.READ_REQUIRES_AUTHENTICATION,
|
|
)
|
|
],
|
|
primary=False,
|
|
)
|
|
battery_service.handle = 0x0014
|
|
battery_service.end_group_handle = 0x0016
|
|
devices[0].gatt_server.add_attribute(
|
|
gatt.IncludedServiceDeclaration(battery_service)
|
|
)
|
|
c = gatt.Characteristic(
|
|
'2A18',
|
|
properties=(
|
|
gatt.Characteristic.Properties.READ
|
|
| gatt.Characteristic.Properties.INDICATE
|
|
| gatt.Characteristic.Properties.EXTENDED_PROPERTIES
|
|
),
|
|
permissions=gatt.Characteristic.Permissions.READ_REQUIRES_AUTHENTICATION,
|
|
)
|
|
devices[0].gatt_server.add_attribute(
|
|
gatt.CharacteristicDeclaration(c, devices[0].gatt_server.next_handle() + 1)
|
|
)
|
|
devices[0].gatt_server.add_attribute(c)
|
|
devices[0].gatt_server.add_attribute(
|
|
gatt.Descriptor(
|
|
gatt.GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
|
|
gatt.Descriptor.Permissions.READ_REQUIRES_AUTHENTICATION,
|
|
b'\x02\x00',
|
|
),
|
|
)
|
|
devices[0].gatt_server.add_attribute(
|
|
gatt.Descriptor(
|
|
gatt.GATT_CHARACTERISTIC_EXTENDED_PROPERTIES_DESCRIPTOR,
|
|
gatt.Descriptor.Permissions.READ_REQUIRES_AUTHENTICATION,
|
|
b'\x00\x00',
|
|
),
|
|
)
|
|
devices[0].add_service(battery_service)
|
|
|
|
peer = device.Peer(devices.connections[1])
|
|
client = await peer.discover_service_and_create_proxy(
|
|
gatt_service.GenericAttributeProfileServiceProxy
|
|
)
|
|
assert client.database_hash_characteristic
|
|
assert await client.database_hash_characteristic.read_value() == bytes.fromhex(
|
|
'F1CA2D48ECF58BAC8A8830BBB9FBA990'
|
|
)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@pytest.mark.asyncio
|
|
async def test_service_changed():
|
|
devices = await test_utils.TwoDevices.create_with_connection()
|
|
assert (service := devices[0].gatt_service)
|
|
|
|
peer = device.Peer(devices.connections[1])
|
|
assert (
|
|
client := await peer.discover_service_and_create_proxy(
|
|
gatt_service.GenericAttributeProfileServiceProxy
|
|
)
|
|
)
|
|
assert client.service_changed_characteristic
|
|
indications = []
|
|
await client.service_changed_characteristic.subscribe(
|
|
indications.append, prefer_notify=False
|
|
)
|
|
await devices[0].indicate_subscribers(
|
|
service.service_changed_characteristic, b'1234'
|
|
)
|
|
await test_utils.async_barrier()
|
|
assert indications[0] == b'1234'
|