Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[chiptool.py] Add some mechanism to add additional custom pseudo clus… #26694

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ def __init__(self, clusters: list[PseudoCluster]):
def supports(self, request) -> bool:
return False if self.__get_command(request) is None else True

def add(self, cluster: PseudoCluster):
self.clusters.append(cluster)

async def execute(self, request):
status = {'error': 'FAILURE'}

Expand Down
1 change: 1 addition & 0 deletions scripts/tests/chiptest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def _GetInDevelopmentTests() -> Set[str]:
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
}

Expand Down
14 changes: 10 additions & 4 deletions scripts/tests/yaml/chiptool.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
from runner import CONTEXT_SETTINGS, chiptool, runner_base
from tests_logger import TestColoredLogPrinter, WebSocketRunnerLogger

_DEFAULT_EXTENSIONS_DIR = 'scripts/tests/yaml/extensions'


@click.pass_context
def send_yaml_command(ctx, test_name: str, server_path: str, server_arguments: str, pics: str, commands: list[str]):
kwargs = {'test_name': test_name, 'pics': pics}
def send_yaml_command(ctx, test_name: str, server_path: str, server_arguments: str, pics: str, additional_pseudo_clusters_directory: str, commands: list[str]):
kwargs = {'test_name': test_name, 'pics': pics, 'additional_pseudo_clusters_directory': additional_pseudo_clusters_directory}

index = 0
while len(commands) - index > 1:
Expand All @@ -40,6 +42,7 @@ def send_yaml_command(ctx, test_name: str, server_path: str, server_arguments: s

del ctx.params['commands']
del ctx.params['pics']
del ctx.params['additional_pseudo_clusters_directory']

return ctx.forward(chiptool)

Expand Down Expand Up @@ -89,6 +92,8 @@ def chiptool_runner_options(f):
help='Do not stop running the test suite on first error.')(f)
f = click.option('--PICS', type=click.Path(exists=True), show_default=True, default=_DEFAULT_PICS_FILE,
help='Path to the PICS file to use.')(f)
f = click.option('--additional_pseudo_clusters_directory', type=click.Path(), show_default=True, default=_DEFAULT_EXTENSIONS_DIR,
help='Path to a directory containing additional pseudo clusters.')(f)
return f


Expand Down Expand Up @@ -120,14 +125,15 @@ def maybe_update_stop_on_error(ctx):
@click.argument('commands', nargs=-1)
@chiptool_runner_options
@click.pass_context
def chiptool_py(ctx, commands: list[str], server_path: str, server_name: str, server_arguments: str, trace_file: str, trace_decode: bool, delay_in_ms: int, continueonfailure: bool, pics: str):
def chiptool_py(ctx, commands: list[str], server_path: str, server_name: str, server_arguments: str, trace_file: str, trace_decode: bool, delay_in_ms: int, continueonfailure: bool, pics: str, additional_pseudo_clusters_directory: str):
success = False

server_arguments = maybe_update_server_arguments(ctx)
maybe_update_stop_on_error(ctx)

if len(commands) > 1 and commands[0] == 'tests':
success = send_yaml_command(commands[1], server_path, server_arguments, pics, commands[2:])
success = send_yaml_command(commands[1], server_path, server_arguments, pics,
additional_pseudo_clusters_directory, commands[2:])
else:
if server_path is None and server_name:
paths_finder = PathsFinder()
Expand Down
Empty file.
72 changes: 72 additions & 0 deletions scripts/tests/yaml/extensions/example_cluster.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#
# Copyright (c) 2023 Project CHIP Authors
#
# 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
#
# http://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.


from matter_yamltests.pseudo_clusters.pseudo_cluster import PseudoCluster


class example_cluster(PseudoCluster):
name = 'ExampleCluster'

async def CommandSuccess(self, request):
return {}

async def CommandError(self, request):
return {'error': 'UNSUPPORTED_COMMAND'}

async def CommandWithReturnValues(self, request):
rv = {
'BooleanTrue': True,
'BooleanFalse': False,
'PositiveNumber': 123456789,
'NegativeNumber': -123456789,
'ListOfBoolean': [True, False, True],
'Struct': {
'boolean': True,
'number': 1,
'struct': {
'boolean': False,
'number': 2,
},
'list': [
{
'boolean': True,
'number': 1,
},
{
'boolean': False,
'number': 3,
},
]
}
}
return {'value': rv}

async def CommandWithInputValues(self, request):
try:
arg1 = int(self._get_argument_value(request, 'Argument1'))
arg2 = int(self._get_argument_value(request, 'Argument2'))
except NameError:
return {'error': 'INVALID_COMMAND'}

rv = {'ReturnValue': arg1 + arg2}
return {'value': rv}

def _get_argument_value(self, request, name):
for argument in request.arguments['values']:
if argument['name'] == name:
return argument['value']

raise NameError
24 changes: 22 additions & 2 deletions scripts/tests/yaml/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

import relative_importer # isort: split # noqa: F401

import importlib
import os
import sys
import traceback
from dataclasses import dataclass
Expand All @@ -42,6 +44,21 @@
_DEFAULT_PICS_FILE = 'src/app/tests/suites/certification/ci-pics-values'


def get_custom_pseudo_clusters(additional_pseudo_clusters_directory: str):
clusters = get_default_pseudo_clusters()

if additional_pseudo_clusters_directory:
sys.path.insert(0, additional_pseudo_clusters_directory)
for filepath in os.listdir(additional_pseudo_clusters_directory):
if filepath != '__init__.py' and filepath[-3:] == '.py':
module = importlib.import_module(f'{filepath[:-3]}')
constructor = getattr(module, module.__name__)
if constructor:
clusters.add(constructor())

return clusters


def test_parser_options(f):
f = click.option('--configuration_name', type=str, show_default=True, default=_DEFAULT_CONFIG_NAME,
help='Name of the collection configuration json file to use.')(f)
Expand All @@ -55,6 +72,8 @@ def test_parser_options(f):
help='Stop parsing on first error.')(f)
f = click.option('--use_default_pseudo_clusters', type=bool, show_default=True, default=True,
help='If enable this option use the set of default clusters provided by the matter_yamltests package.')(f)
f = click.option('--additional_pseudo_clusters_directory', type=click.Path(), show_default=True, default=None,
help='Path to a directory containing additional pseudo clusters.')(f)
return f


Expand Down Expand Up @@ -229,8 +248,9 @@ def __add_custom_params(self, ctx):
@click.argument('test_name')
@test_parser_options
@click.pass_context
def runner_base(ctx, configuration_directory: str, test_name: str, configuration_name: str, pics: str, specifications_paths: str, stop_on_error: bool, use_default_pseudo_clusters: bool, **kwargs):
pseudo_clusters = get_default_pseudo_clusters() if use_default_pseudo_clusters else PseudoClusters([])
def runner_base(ctx, configuration_directory: str, test_name: str, configuration_name: str, pics: str, specifications_paths: str, stop_on_error: bool, use_default_pseudo_clusters: bool, additional_pseudo_clusters_directory: str, **kwargs):
pseudo_clusters = get_custom_pseudo_clusters(
additional_pseudo_clusters_directory) if use_default_pseudo_clusters else PseudoClusters([])
specifications = SpecDefinitionsFromPaths(specifications_paths.split(','), pseudo_clusters)
tests_finder = TestsFinder(configuration_directory, configuration_name)

Expand Down
78 changes: 78 additions & 0 deletions src/app/tests/suites/TestExampleCluster.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Copyright (c) 2023 Project CHIP Authors
#
# 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
#
# http://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.

name: Example Cluster Tests

config:
cluster: "ExampleCluster"

tests:
- label: "Call a command that returns a success"
command: "CommandSuccess"

- label: "Call a command that returns an error"
command: "CommandError"
response:
error: UNSUPPORTED_COMMAND

- label: "Call a command with some return values"
command: "CommandWithReturnValues"
response:
values:
- name: "BooleanTrue"
value: true
- name: "BooleanFalse"
value: false
- name: "PositiveNumber"
value: 123456789
- name: "NegativeNumber"
value: -123456789
- name: "ListOfBoolean"
value: [true, false, true]
- name: "Struct"
value:
{
"boolean": true,
"number": 1,
"struct": { "boolean": false, "number": 2 },
"list":
[
{ "boolean": true, "number": 1 },
{ "boolean": false, "number": 3 },
],
}

- label: "Call a command with some input values"
command: "CommandWithInputValues"
arguments:
values:
- name: "Argument1"
value: 123
- name: "Argument2"
value: 456
response:
- values:
- name: "ReturnValue"
value: 579

- label:
"Call a command with some input values but expect a failure this time
because some argument is missing"
command: "CommandWithInputValues"
arguments:
values:
- name: "Argument1"
value: 123
response:
error: INVALID_COMMAND