mirror of
https://github.com/google/bumble.git
synced 2026-06-13 09:32:27 +00:00
Merge pull request #387 from google/gbg/async-gatt-server
support async read/write for characteristic values
This commit is contained in:
+2
-1
@@ -48,7 +48,8 @@ from bumble.profiles.bap import (
|
||||
PublishedAudioCapabilitiesService,
|
||||
PublishedAudioCapabilitiesServiceProxy,
|
||||
)
|
||||
from .test_utils import TwoDevices
|
||||
from tests.test_utils import TwoDevices
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Logging
|
||||
|
||||
+76
-31
@@ -20,11 +20,10 @@ import logging
|
||||
import os
|
||||
import struct
|
||||
import pytest
|
||||
from unittest.mock import Mock, ANY
|
||||
from unittest.mock import AsyncMock, Mock, ANY
|
||||
|
||||
from bumble.controller import Controller
|
||||
from bumble.gatt_client import CharacteristicProxy
|
||||
from bumble.gatt_server import Server
|
||||
from bumble.link import LocalLink
|
||||
from bumble.device import Device, Peer
|
||||
from bumble.host import Host
|
||||
@@ -120,9 +119,9 @@ async def test_characteristic_encoding():
|
||||
Characteristic.READABLE,
|
||||
123,
|
||||
)
|
||||
x = c.read_value(None)
|
||||
x = await c.read_value(None)
|
||||
assert x == bytes([123])
|
||||
c.write_value(None, bytes([122]))
|
||||
await c.write_value(None, bytes([122]))
|
||||
assert c.value == 122
|
||||
|
||||
class FooProxy(CharacteristicProxy):
|
||||
@@ -152,7 +151,22 @@ async def test_characteristic_encoding():
|
||||
bytes([123]),
|
||||
)
|
||||
|
||||
service = Service('3A657F47-D34F-46B3-B1EC-698E29B6B829', [characteristic])
|
||||
async def async_read(connection):
|
||||
return 0x05060708
|
||||
|
||||
async_characteristic = PackedCharacteristicAdapter(
|
||||
Characteristic(
|
||||
'2AB7E91B-43E8-4F73-AC3B-80C1683B47F9',
|
||||
Characteristic.Properties.READ,
|
||||
Characteristic.READABLE,
|
||||
CharacteristicValue(read=async_read),
|
||||
),
|
||||
'>I',
|
||||
)
|
||||
|
||||
service = Service(
|
||||
'3A657F47-D34F-46B3-B1EC-698E29B6B829', [characteristic, async_characteristic]
|
||||
)
|
||||
server.add_service(service)
|
||||
|
||||
await client.power_on()
|
||||
@@ -184,6 +198,13 @@ async def test_characteristic_encoding():
|
||||
await async_barrier()
|
||||
assert characteristic.value == bytes([50])
|
||||
|
||||
c2 = peer.get_characteristics_by_uuid(async_characteristic.uuid)
|
||||
assert len(c2) == 1
|
||||
c2 = c2[0]
|
||||
cd2 = PackedCharacteristicAdapter(c2, ">I")
|
||||
cd2v = await cd2.read_value()
|
||||
assert cd2v == 0x05060708
|
||||
|
||||
last_change = None
|
||||
|
||||
def on_change(value):
|
||||
@@ -285,7 +306,8 @@ async def test_attribute_getters():
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def test_CharacteristicAdapter():
|
||||
@pytest.mark.asyncio
|
||||
async def test_CharacteristicAdapter():
|
||||
# Check that the CharacteristicAdapter base class is transparent
|
||||
v = bytes([1, 2, 3])
|
||||
c = Characteristic(
|
||||
@@ -296,11 +318,11 @@ def test_CharacteristicAdapter():
|
||||
)
|
||||
a = CharacteristicAdapter(c)
|
||||
|
||||
value = a.read_value(None)
|
||||
value = await a.read_value(None)
|
||||
assert value == v
|
||||
|
||||
v = bytes([3, 4, 5])
|
||||
a.write_value(None, v)
|
||||
await a.write_value(None, v)
|
||||
assert c.value == v
|
||||
|
||||
# Simple delegated adapter
|
||||
@@ -308,11 +330,11 @@ def test_CharacteristicAdapter():
|
||||
c, lambda x: bytes(reversed(x)), lambda x: bytes(reversed(x))
|
||||
)
|
||||
|
||||
value = a.read_value(None)
|
||||
value = await a.read_value(None)
|
||||
assert value == bytes(reversed(v))
|
||||
|
||||
v = bytes([3, 4, 5])
|
||||
a.write_value(None, v)
|
||||
await a.write_value(None, v)
|
||||
assert a.value == bytes(reversed(v))
|
||||
|
||||
# Packed adapter with single element format
|
||||
@@ -321,10 +343,10 @@ def test_CharacteristicAdapter():
|
||||
c.value = v
|
||||
a = PackedCharacteristicAdapter(c, '>H')
|
||||
|
||||
value = a.read_value(None)
|
||||
value = await a.read_value(None)
|
||||
assert value == pv
|
||||
c.value = None
|
||||
a.write_value(None, pv)
|
||||
await a.write_value(None, pv)
|
||||
assert a.value == v
|
||||
|
||||
# Packed adapter with multi-element format
|
||||
@@ -334,10 +356,10 @@ def test_CharacteristicAdapter():
|
||||
c.value = (v1, v2)
|
||||
a = PackedCharacteristicAdapter(c, '>HH')
|
||||
|
||||
value = a.read_value(None)
|
||||
value = await a.read_value(None)
|
||||
assert value == pv
|
||||
c.value = None
|
||||
a.write_value(None, pv)
|
||||
await a.write_value(None, pv)
|
||||
assert a.value == (v1, v2)
|
||||
|
||||
# Mapped adapter
|
||||
@@ -348,10 +370,10 @@ def test_CharacteristicAdapter():
|
||||
c.value = mapped
|
||||
a = MappedCharacteristicAdapter(c, '>HH', ('v1', 'v2'))
|
||||
|
||||
value = a.read_value(None)
|
||||
value = await a.read_value(None)
|
||||
assert value == pv
|
||||
c.value = None
|
||||
a.write_value(None, pv)
|
||||
await a.write_value(None, pv)
|
||||
assert a.value == mapped
|
||||
|
||||
# UTF-8 adapter
|
||||
@@ -360,27 +382,49 @@ def test_CharacteristicAdapter():
|
||||
c.value = v
|
||||
a = UTF8CharacteristicAdapter(c)
|
||||
|
||||
value = a.read_value(None)
|
||||
value = await a.read_value(None)
|
||||
assert value == ev
|
||||
c.value = None
|
||||
a.write_value(None, ev)
|
||||
await a.write_value(None, ev)
|
||||
assert a.value == v
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def test_CharacteristicValue():
|
||||
@pytest.mark.asyncio
|
||||
async def test_CharacteristicValue():
|
||||
b = bytes([1, 2, 3])
|
||||
c = CharacteristicValue(read=lambda _: b)
|
||||
x = c.read(None)
|
||||
|
||||
async def read_value(connection):
|
||||
return b
|
||||
|
||||
c = CharacteristicValue(read=read_value)
|
||||
x = await c.read(None)
|
||||
assert x == b
|
||||
|
||||
result = []
|
||||
c = CharacteristicValue(
|
||||
write=lambda connection, value: result.append((connection, value))
|
||||
)
|
||||
m = Mock()
|
||||
c = CharacteristicValue(write=m)
|
||||
z = object()
|
||||
c.write(z, b)
|
||||
assert result == [(z, b)]
|
||||
m.assert_called_once_with(z, b)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@pytest.mark.asyncio
|
||||
async def test_CharacteristicValue_async():
|
||||
b = bytes([1, 2, 3])
|
||||
|
||||
async def read_value(connection):
|
||||
return b
|
||||
|
||||
c = CharacteristicValue(read=read_value)
|
||||
x = await c.read(None)
|
||||
assert x == b
|
||||
|
||||
m = AsyncMock()
|
||||
c = CharacteristicValue(write=m)
|
||||
z = object()
|
||||
await c.write(z, b)
|
||||
m.assert_called_once_with(z, b)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -961,12 +1005,18 @@ Descriptor(handle=0x0009, type=UUID-16:2902 (Client Characteristic Configuration
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
async def async_main():
|
||||
test_UUID()
|
||||
test_ATT_Error_Response()
|
||||
test_ATT_Read_By_Group_Type_Request()
|
||||
await test_read_write()
|
||||
await test_read_write2()
|
||||
await test_subscribe_notify()
|
||||
await test_unsubscribe()
|
||||
await test_characteristic_encoding()
|
||||
await test_mtu_exchange()
|
||||
await test_CharacteristicValue()
|
||||
await test_CharacteristicValue_async()
|
||||
await test_CharacteristicAdapter()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -1105,9 +1155,4 @@ def test_get_attribute_group():
|
||||
# -----------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'INFO').upper())
|
||||
test_UUID()
|
||||
test_ATT_Error_Response()
|
||||
test_ATT_Read_By_Group_Type_Request()
|
||||
test_CharacteristicValue()
|
||||
test_CharacteristicAdapter()
|
||||
asyncio.run(async_main())
|
||||
|
||||
Reference in New Issue
Block a user