Bluetooth SDP autotest: tests for existing attributes
This CL adds the support for continuation state in Service Attribute
Requests and a test for it. It also adds some tests for existing
attributes of existing services.
BUG=chromium:329044
TEST=test_that --board ${BOARD} ${HOSTNAME} bluetooth_SDP_ServiceAttributeRequest
Change-Id: Ica7626be9b46ebb238e169ee0efea091761a35d1
Reviewed-on: https://chromium-review.googlesource.com/202788
Tested-by: Artem Rakhov <arakhov@chromium.org>
Reviewed-by: Fang Deng <fdeng@chromium.org>
Reviewed-by: Arman Uguray <armansito@chromium.org>
Commit-Queue: Artem Rakhov <arakhov@chromium.org>
diff --git a/client/common_lib/cros/bluetooth/bluetooth_sdp_socket.py b/client/common_lib/cros/bluetooth/bluetooth_sdp_socket.py
index 306db73..2c04096 100644
--- a/client/common_lib/cros/bluetooth/bluetooth_sdp_socket.py
+++ b/client/common_lib/cros/bluetooth/bluetooth_sdp_socket.py
@@ -297,9 +297,9 @@
restrictions or if the response has an incorrect code
"""
- if max_rec_cnt < 1 or max_rec_cnt > 0xFFFF:
+ if max_rec_cnt < 1 or max_rec_cnt > 65535:
raise BluetoothSDPSocketError('MaximumServiceRecordCount must be '
- 'between 1 and 0xFFFF, inclusive')
+ 'between 1 and 65535, inclusive')
if len(uuids) > SDP_MAX_SSR_UUIDS_CNT:
raise BluetoothSDPSocketError('Too many UUIDs')
@@ -446,22 +446,6 @@
raise BluetoothSDPSocketError('Invalid size descriptor')
- def _unpack_attr_ids(self, response):
- """Unpack Service Attribute Response
-
- @param response: body of raw Service Attribute Response.
-
- @return dictionary of {attribute id : value}
-
- """
- byte_cnt, = struct.unpack_from('>H', response)
- response = response[2:]
- id_values_list, scanned = self._unpack_sdp_data_element(response)
- if scanned != byte_cnt:
- raise BluetoothSDPSocketError('Incorrect size of SDP data element')
- return id_values_list, byte_cnt
-
-
def service_attribute_request(self, handle, max_attr_byte_count, attr_ids):
"""Send a Service Attribute Request
@@ -477,15 +461,15 @@
restrictions or if the response has an incorrect code
"""
- if max_attr_byte_count < 7 or max_attr_byte_count > 0xFFFF:
+ if max_attr_byte_count < 7 or max_attr_byte_count > 65535:
raise BluetoothSDPSocketError('MaximumAttributeByteCount must be '
- 'between 7 and 0xFFFF, inclusive')
+ 'between 7 and 65535, inclusive')
pattern = (struct.pack('>I', handle) +
struct.pack('>H', max_attr_byte_count) +
self._pack_attr_ids(attr_ids))
cont_state = '\0'
- id_values_list = []
+ complete_response = ''
while True:
request = pattern + cont_state
@@ -499,18 +483,19 @@
if code != SDP_SVC_ATTR_RSP:
raise BluetoothSDPSocketError('Incorrect response code')
- cur_values, response_byte_count = self._unpack_attr_ids(response)
-
+ response_byte_count, = struct.unpack_from('>H', response)
if response_byte_count > max_attr_byte_count:
raise BluetoothSDPSocketError('AttributeListByteCount exceeds'
'MaximumAttributeByteCount')
- id_values_list.extend(cur_values)
+ response = response[2:]
+ complete_response += response[:response_byte_count]
+ cont_state = response[response_byte_count:]
- cont_state = response[2 + response_byte_count:]
if cont_state == '\0':
break
+ id_values_list = self._unpack_sdp_data_element(complete_response)[0]
if len(id_values_list) % 2 == 1:
raise BluetoothSDPSocketError('Length of returned list is odd')
diff --git a/server/site_tests/bluetooth_SDP_ServiceAttributeRequest/bluetooth_SDP_ServiceAttributeRequest.py b/server/site_tests/bluetooth_SDP_ServiceAttributeRequest/bluetooth_SDP_ServiceAttributeRequest.py
index df53ae3..ec42c76 100644
--- a/server/site_tests/bluetooth_SDP_ServiceAttributeRequest/bluetooth_SDP_ServiceAttributeRequest.py
+++ b/server/site_tests/bluetooth_SDP_ServiceAttributeRequest/bluetooth_SDP_ServiceAttributeRequest.py
@@ -31,6 +31,16 @@
L2CAP_UUID = 0x0100
ATT_UUID = 0x0007
+ PNP_INFORMATION_CLASS_ID = 0x1200
+ MIN_ATTR_BYTE_CNT = 7
+
+ VERSION_NUMBER_LIST_ATTR_ID = 0x0200
+ SERVICE_DATABASE_STATE_ATTR_ID = 0x0201
+
+ AVRCP_TG_CLASS_ID = 0x110c
+ PROFILE_DESCRIPTOR_LIST_ATTR_ID = 0x0009
+ ADDITIONAL_PROTOCOLLIST_ATTR_ID = 0x000D
+
def get_single_handle(self, class_id):
"""Send a Service Search Request to get a handle for specific class ID.
@@ -66,6 +76,27 @@
return res == [self.SERVICE_RECORD_HANDLE_ATTR_ID, record_handle]
+ def get_attribute(self, class_id, attr_id):
+ """Get a single attribute of a single service
+
+ @param class_id: Class ID of service to check.
+ @param attr_id: ID of attribute to check.
+
+ @return attribute value if attribute exists, None otherwise
+
+ """
+ record_handle = self.get_single_handle(class_id)
+ if record_handle == -1:
+ return False
+
+ res = self.tester.service_attribute_request(
+ record_handle, self.MAX_ATTR_BYTE_CNT, [attr_id])
+
+ if isinstance(res, list) and len(res) == 2 and res[0] == attr_id:
+ return res[1]
+ return None
+
+
def test_attribute(self, class_id, attr_id, attr_value):
"""Test a single attribute of a single service
@@ -142,6 +173,69 @@
[self.ATT_UUID, 1, 8]])
+ def test_continuation_state(self):
+ """Implementation of test TP/SERVER/SA/BV-03-C from SDP Specification.
+
+ @return True if test passes, False if test fails
+
+ """
+ record_handle = self.get_single_handle(self.PNP_INFORMATION_CLASS_ID)
+ if record_handle == -1:
+ return False
+
+ res = self.tester.service_attribute_request(
+ record_handle, self.MIN_ATTR_BYTE_CNT, [[0, 0xFFFF]])
+
+ return isinstance(res, list) and res != []
+
+
+ def test_version_list_attribute(self):
+ """Implementation of test TP/SERVER/SA/BV-15-C from SDP Specification.
+
+ @return True if test passes, False if test fails
+
+ """
+ version_list = self.get_attribute(self.SDP_SERVER_CLASS_ID,
+ self.VERSION_NUMBER_LIST_ATTR_ID)
+ return isinstance(version_list, list) and version_list != []
+
+
+ def test_service_database_state_attribute(self):
+ """Implementation of test TP/SERVER/SA/BV-16-C from SDP Specification.
+
+ @return True if test passes, False if test fails
+
+ """
+ state = self.get_attribute(self.SDP_SERVER_CLASS_ID,
+ self.SERVICE_DATABASE_STATE_ATTR_ID)
+ return isinstance(state, int)
+
+
+ def test_profile_descriptor_list_attribute(self):
+ """Implementation of test TP/SERVER/SA/BV-17-C from SDP Specification.
+
+ @return True if test passes, False if test fails
+
+ """
+ profile_list = self.get_attribute(self.PNP_INFORMATION_CLASS_ID,
+ self.PROFILE_DESCRIPTOR_LIST_ATTR_ID)
+ return (isinstance(profile_list, list) and len(profile_list) == 1 and
+ isinstance(profile_list[0], list) and
+ len(profile_list[0]) == 2 and
+ profile_list[0][0] == self.PNP_INFORMATION_CLASS_ID)
+
+
+ def test_additional_protocol_descriptor_list_attribute(self):
+ """Implementation of test TP/SERVER/SA/BV-18-C from SDP Specification.
+
+ @return True if test passes, False if test fails
+
+ """
+ protocol_list = self.get_attribute(self.AVRCP_TG_CLASS_ID,
+ self.ADDITIONAL_PROTOCOLLIST_ATTR_ID)
+ return isinstance(protocol_list, list) and protocol_list != []
+
+
def correct_request(self):
"""Run basic tests for Service Attribute Request.
@@ -156,7 +250,12 @@
self.test_icon_url_attribute() and
self.test_documentation_url_attribute() and
self.test_client_executable_url_attribute() and
- self.test_protocol_descriptor_list_attribute())
+ self.test_protocol_descriptor_list_attribute() and
+ self.test_continuation_state() and
+ self.test_version_list_attribute() and
+ self.test_service_database_state_attribute() and
+ self.test_profile_descriptor_list_attribute() and
+ self.test_additional_protocol_descriptor_list_attribute())
def run_once(self):
diff --git a/server/site_tests/bluetooth_SDP_ServiceAttributeRequest/control b/server/site_tests/bluetooth_SDP_ServiceAttributeRequest/control
index c0f9e8f..ea89914 100644
--- a/server/site_tests/bluetooth_SDP_ServiceAttributeRequest/control
+++ b/server/site_tests/bluetooth_SDP_ServiceAttributeRequest/control
@@ -17,15 +17,22 @@
The tester sends Service Search Request and Service Attribute Request to the DUT
to ensure that it is able to response with different attributes:
ServiceRecordHandle, BrowseGroupList, DocumentationURL, ClientExecutableURL,
-IconURL, ProtocolDescriptorList.
+IconURL, ProtocolDescriptorList, VersionNumberList, ServiceDatabaseState,
+BluetoothProfileDescriptorList, AdditionalProtocolDescriptorLists.
+It also checks that responses with continuation state work properly.
This test covers the Bluetooth SIG test cases:
TP/SERVER/SA/BV-01-C
+TP/SERVER/SA/BV-03-C
+TP/SERVER/SA/BV-05-C
TP/SERVER/SA/BV-08-C
TP/SERVER/SA/BV-11-C
+TP/SERVER/SA/BV-15-C
+TP/SERVER/SA/BV-16-C
+TP/SERVER/SA/BV-17-C
TP/SERVER/SA/BV-18-C
TP/SERVER/SA/BV-19-C
-TP/SERVER/SA/BV-05-C
+TP/SERVER/SA/BV-21-C
"""
from autotest_lib.server.cros.bluetooth import bluetooth_tester