Skip to content

Commit

Permalink
[chip-tool] Add AnyCommands aliases (#26755)
Browse files Browse the repository at this point in the history
  • Loading branch information
vivien-apple authored and pull[bot] committed Jan 11, 2024
1 parent e463508 commit 1285784
Show file tree
Hide file tree
Showing 7 changed files with 769 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,14 @@ def __translate_names(self, payloads):
# Raise an error since the other fields probably needs to be translated too.
raise KeyError(f'Error: field "{key}" not supported')

if value is None and (key == _CLUSTER or key == _RESPONSE or key == _ATTRIBUTE or key == _EVENT):
if value is None and (key == _CLUSTER or key == _RESPONSE or key == _ATTRIBUTE or key == _EVENT) and _ERROR not in payload:
# If the definition for this cluster/command/attribute/event is missing, there is not
# much we can do to convert the response to the proper format. It usually indicates that
# the cluster definition is missing something. So we just raise an exception to tell the
# user something is wrong and the cluster definition needs to be updated.
# The only exception being when the definition can not be found but the returned payload
# contains an error. It could be because the payload is for an unknown cluster/command/attribute/event
# in which case we obviously don't have a definition for it.
cluster_code = hex(payload[_CLUSTER_ID])
if key == _CLUSTER:
raise KeyError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,88 @@
import json
import re

_ANY_COMMANDS_LIST = [
'ReadById',
'WriteById',
'SubscribeById',
'ReadEventById',
'SubscribeEventById',
'ReadAll',
'SubscribeAll',
]

_ANY_COMMANDS_LIST_ARGUMENTS_WITH_WILDCARDS = [
'ClusterId',
'AttributeId',
'EventId',
]


_ALIASES = {
'AnyCommands': {
'alias': 'any',
'commands': {
'CommandById': {
'alias': 'command-by-id',
'arguments': {
'ClusterId': 'cluster-id',
'CommandId': 'command-id',
},
},
'ReadById': {
'alias': 'read-by-id',
'arguments': {
'ClusterId': 'cluster-ids',
'AttributeId': 'attribute-ids',
},
},
'WriteById': {
'alias': 'write-by-id',
'arguments': {
'ClusterId': 'cluster-ids',
'AttributeId': 'attribute-ids',
'Value': 'attribute-values'
},
},
'SubscribeById': {
'alias': 'subscribe-by-id',
'arguments': {
'ClusterId': 'cluster-ids',
'AttributeId': 'attribute-ids',
},
},
'ReadEventById': {
'alias': 'read-event-by-id',
'arguments': {
'ClusterId': 'cluster-id',
'EventId': 'event-id',
},
},
'SubscribeEventById': {
'alias': 'subscribe-event-by-id',
'arguments': {
'ClusterId': 'cluster-id',
'EventId': 'event-id',
},
},
'ReadAll': {
'alias': 'read-all',
'arguments': {
'ClusterId': 'cluster-ids',
'AttributeId': 'attribute-ids',
'EventId': 'event-ids',
},
},
'SubscribeAll': {
'alias': 'subscribe-all',
'arguments': {
'ClusterId': 'cluster-ids',
'AttributeId': 'attribute-ids',
'EventId': 'event-ids',
},
},
}
},
'CommissionerCommands': {
'alias': 'pairing',
'commands': {
Expand Down Expand Up @@ -199,7 +280,7 @@ def __maybe_add_endpoint(self, rv, request):
endpoint_argument_name = 'endpoint-id-ignored-for-group-commands'
endpoint_argument_value = request.endpoint

if (request.is_attribute and not request.command == "writeAttribute") or request.is_event:
if (request.is_attribute and not request.command == "writeAttribute") or request.is_event or (request.command in _ANY_COMMANDS_LIST and not request.command == "WriteById"):
endpoint_argument_name = 'endpoint-ids'

if rv:
Expand All @@ -213,7 +294,8 @@ def __maybe_add_command_arguments(self, rv, request):

for entry in request.arguments['values']:
name = self.__get_argument_name(request, entry)
value = self.__encode_value(entry['value'])
value = self.__encode_value(
request.command, entry.get('name'), entry['value'])
if rv:
rv += ', '
rv += f'"{name}":{value}'
Expand Down Expand Up @@ -242,11 +324,24 @@ def __maybe_add(self, rv, value, name):
rv += f'"{name}":"{value}"'
return rv

def __encode_value(self, value):
def __encode_value(self, command_name, argument_name, value):
value = self.__encode_wildcards(command_name, argument_name, value)
value = self.__encode_octet_strings(value)
value = self.__lower_camel_case_member_fields(value)
return self.__convert_to_json_string(value)

def __encode_wildcards(self, command_name, argument_name, value):
if value != '*':
return value

# maybe a wildcard
if command_name in _ANY_COMMANDS_LIST and argument_name in _ANY_COMMANDS_LIST_ARGUMENTS_WITH_WILDCARDS:
# translate * to wildcard constant
return 0xFFFFFFFF

# return actual '*' as value ... not a wildcard-compatible argument
return value

def __encode_octet_strings(self, value):
if isinstance(value, list):
value = [self.__encode_octet_strings(entry) for entry in value]
Expand Down
16 changes: 14 additions & 2 deletions scripts/py_matter_yamltests/matter_yamltests/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@
from .pics_checker import PICSChecker
from .yaml_loader import YamlLoader

ANY_COMMANDS_CLUSTER_NAME = 'AnyCommands'
ANY_COMMANDS_LIST = [
'CommandById',
'ReadById',
'WriteById',
'SubscribeById',
'ReadEventById',
'SubscribeEventById',
'ReadAll',
'SubscribeAll',
]


class UnknownPathQualifierError(TestStepError):
"""Raise when an attribute/command/event name is not found in the definitions."""
Expand Down Expand Up @@ -235,7 +247,7 @@ def __init__(self, test: dict, config: dict, definitions: SpecDefinitions, pics_

def _update_mappings(self, test: dict, definitions: SpecDefinitions):
cluster_name = self.cluster
if definitions is None or not definitions.has_cluster_by_name(cluster_name):
if definitions is None or not definitions.has_cluster_by_name(cluster_name) or cluster_name == ANY_COMMANDS_CLUSTER_NAME or self.command in ANY_COMMANDS_LIST:
self.argument_mapping = None
self.response_mapping = None
self.response_mapping_name = None
Expand Down Expand Up @@ -756,7 +768,7 @@ def _response_values_validation(self, expected_response, received_response, resu
break

received_value = received_response.get('value')
if not self.is_attribute and not self.is_event:
if not self.is_attribute and not self.is_event and not (self.command in ANY_COMMANDS_LIST):
expected_name = value.get('name')
if expected_name not in received_value:
result.error(check_type, error_name_does_not_exist.format(
Expand Down
11 changes: 5 additions & 6 deletions scripts/tests/chiptest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,16 @@ def _GetSlowTests() -> Set[str]:


def _GetInDevelopmentTests() -> Set[str]:
"""Tests that fail in YAML for some reason.
Currently this is empty and returns an empty set, but this is kept around in case
there are tests that are a work in progress.
"""
"""Tests that fail in YAML for some reason."""
return {
"Test_AddNewFabricFromExistingFabric.yaml", # chip-repl does not support GetCommissionerRootCertificate and IssueNocChain command
"TestEqualities.yaml", # chip-repl does not support pseudo-cluster commands that return a value
"TestExampleCluster.yaml", # chip-repl does not load custom pseudo clusters
"TestClientMonitoringCluster.yaml", # Client Monitoring Tests need a rework after the XML update
"Test_TC_TIMESYNC_1_1.yaml" # Time sync SDK is not yet ready
"Test_TC_TIMESYNC_1_1.yaml", # Time sync SDK is not yet ready
"TestAttributesById.yaml", # chip-repl does not support AnyCommands (06/06/2023)
"TestCommandsById.yaml", # chip-repl does not support AnyCommands (06/06/2023)
"TestEventsById.yaml", # chip-repl does not support AnyCommands (06/06/2023)
}


Expand Down
Loading

0 comments on commit 1285784

Please sign in to comment.