From bfcecfef9867d056838ac3b7004aa06dac7b1058 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Wed, 25 Jan 2023 19:04:49 +0000 Subject: [PATCH 1/3] Add support for default pseudo cluster --- src/controller/python/chip/yaml/runner.py | 43 ++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/controller/python/chip/yaml/runner.py b/src/controller/python/chip/yaml/runner.py index 9dcd1fc212693b..a4d4719b76bfb8 100644 --- a/src/controller/python/chip/yaml/runner.py +++ b/src/controller/python/chip/yaml/runner.py @@ -27,10 +27,16 @@ import stringcase from chip import ChipDeviceCtrl from chip.clusters.Attribute import AttributeStatus, SubscriptionTransaction, TypedAttributePath, ValueDecodeFailure +from chip.exceptions import ChipStackError from chip.yaml.errors import ParsingError, UnexpectedParsingError +from matter_yamltests.pseudo_clusters.clusters.delay_commands import DelayCommands +from matter_yamltests.pseudo_clusters.clusters.log_commands import LogCommands +from matter_yamltests.pseudo_clusters.clusters.system_commands import SystemCommands +from matter_yamltests.pseudo_clusters.pseudo_clusters import PseudoClusters from .data_model_lookup import * +_PSEUDO_CLUSTERS = PseudoClusters([DelayCommands(), LogCommands(), SystemCommands()]) logger = logging.getLogger('YamlParser') @@ -96,6 +102,18 @@ def run_action(self, dev_ctrl: ChipDeviceCtrl) -> _ActionResult: pass +class DefaultPseudoCluster(BaseAction): + def __init__(self, test_step): + super().__init__(test_step) + self._test_step = test_step + if not _PSEUDO_CLUSTERS.supports(test_step): + raise ParsingError(f'Default cluster {test_step.cluster} {test_step.command}, not supported') + + def run_action(self, dev_ctrl: ChipDeviceCtrl) -> _ActionResult: + resp = asyncio.run(_PSEUDO_CLUSTERS.execute(self._test_step)) + return _ActionResult(status=_ActionStatus.SUCCESS, response=None) + + class InvokeAction(BaseAction): '''Single invoke action to be executed.''' @@ -213,6 +231,13 @@ def run_action(self, dev_ctrl: ChipDeviceCtrl) -> _ActionResult: fabricFiltered=self._fabric_filtered)) except chip.interaction_model.InteractionModelError as error: return _ActionResult(status=_ActionStatus.ERROR, response=error) + except ChipStackError as error: + _CHIP_TIMEOUT_ERROR = 50 + if error.err == _CHIP_TIMEOUT_ERROR: + return _ActionResult(status=_ActionStatus.ERROR, response=error) + # For now it is unsure if all ChipStackError are supposed to be intentional. + # As a result we simply re-raise the error. + raise error return self.parse_raw_response(raw_resp) @@ -254,7 +279,9 @@ def __init__(self, test_step): args = test_step.arguments['values'] request_data_as_dict = Converter.convert_list_of_name_value_pair_to_dict(args) - self._expire_existing_session = request_data_as_dict.get('expireExistingSession', False) + # Only if expire existing session is explicitly false do we want to supress expiring + # the session. + self._expire_existing_session = request_data_as_dict.get('expireExistingSession', True) if 'timeout' in request_data_as_dict: # Timeout is provided in seconds we need to conver to milliseconds. self._timeout_ms = request_data_as_dict['timeout'] * 1000 @@ -579,6 +606,12 @@ def _commissioner_command_action_factory(self, test_step): except ParsingError: return None + def _default_pseudo_cluster(self, test_step): + try: + return DefaultPseudoCluster(test_step) + except ParsingError: + return None + def encode(self, request) -> BaseAction: action = None cluster = request.cluster.replace(' ', '').replace('/', '') @@ -605,6 +638,10 @@ def encode(self, request) -> BaseAction: else: action = self._invoke_action_factory(request, cluster) + if action is None: + # Now we try to create a default pseudo cluster. + action = self._default_pseudo_cluster(request) + if action is None: logger.warn(f"Failed to parse {request.label}") return action @@ -628,6 +665,10 @@ def decode(self, result: _ActionResult): decoded_response['error'] = stringcase.snakecase(response.name).upper() return decoded_response + if isinstance(response, ChipStackError): + decoded_response['error'] = 'FAILURE' + return decoded_response + cluster_name = self._test_spec_definition.get_cluster_name(response.cluster_id) decoded_response['clusterId'] = cluster_name From 23f7d752a0a119f0308ea71e2553a182f471713a Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Mon, 30 Jan 2023 18:56:53 +0000 Subject: [PATCH 2/3] Address PR comment --- src/controller/python/chip/yaml/runner.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/controller/python/chip/yaml/runner.py b/src/controller/python/chip/yaml/runner.py index 9db41cd6d266f9..d4915aea9f559c 100644 --- a/src/controller/python/chip/yaml/runner.py +++ b/src/controller/python/chip/yaml/runner.py @@ -278,10 +278,11 @@ def __init__(self, test_step): args = test_step.arguments['values'] request_data_as_dict = Converter.convert_list_of_name_value_pair_to_dict(args) - # When expireExistingSession is not provided it is true be default. This is because - # expireExistingSession argument was added later on to test a specific CASE situation - # where that specific test case did not want existing session to be expired. For more - # information see PR #20820. + # There's a chance the commissionee may have rebooted before this call here as part of a + # test flow or is just starting out fresh outright. Unless expireExistingSession is + # explicitly set, the default behaviour it so make sure we're not re-using any cached CASE + # sessions that will now be stale and mismatched with the peer, causing subsequent + # interactions to fail. self._expire_existing_session = request_data_as_dict.get('expireExistingSession', True) self._node_id = request_data_as_dict['nodeId'] if 'timeout' in request_data_as_dict: From 5a723a51e46d79a5a3f5c90458ca0f84971bcc04 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Mon, 30 Jan 2023 19:05:39 +0000 Subject: [PATCH 3/3] Address PR comment --- src/controller/python/chip/yaml/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller/python/chip/yaml/runner.py b/src/controller/python/chip/yaml/runner.py index d4915aea9f559c..895fb79d10256c 100644 --- a/src/controller/python/chip/yaml/runner.py +++ b/src/controller/python/chip/yaml/runner.py @@ -280,7 +280,7 @@ def __init__(self, test_step): # There's a chance the commissionee may have rebooted before this call here as part of a # test flow or is just starting out fresh outright. Unless expireExistingSession is - # explicitly set, the default behaviour it so make sure we're not re-using any cached CASE + # explicitly set, the default behaviour it to make sure we're not re-using any cached CASE # sessions that will now be stale and mismatched with the peer, causing subsequent # interactions to fail. self._expire_existing_session = request_data_as_dict.get('expireExistingSession', True)