Skip to content

Commit

Permalink
Refactoring of support test scripts to enhance matter testing infrast…
Browse files Browse the repository at this point in the history
…ructure (#34785)

* Refactoring of the matter testing infrastructure

* Restyled by shfmt

* Manually fix restyle

* Manually fix restyle

* Manually restyle

* Manually fix restyle

* Manually fix restyle

* Renamed testing_support to matter_testing _support

* Fixed the support scripts from matter_testing_support

* Fixed TC_OVENOPSTATE_2_6.py for import command

* replace all os.path.join and such (using _file_) with their own method

* Fixed paths.py for import

* Fixed imports for TC_DeviceConformace.py

* Fixed the broken import for matter_testing

* Make sure modules match master

* Debug the data model files for spec_parsing

* Try to guess data model root

* Restyle

* Moving Test* from python_testing to matter_testing_support

* Removed the tests moved from glob python scripts

* Restyled by isort

* Added taglist_and_topology_test.py to the support tests list

* Restyled by isort

* Fixed the structure for accessing example_pics_xml_basic_info.xml

* Fixing the TC_RVCCLEANM_2_2.py script according to master changes

* Changes according to master

* Fixing structuring of TestMatterTestingSupport.py and TestSpecParsingSupport.py

* Restyled by isort

* Fixed typo on src/python_testing/matter_testing_infrastructure/BUILD.gn tests section

* Fixed import for TC_ICDM_3_2.py

* Fix Import for TC_RVCCLEANM_2_2.py

* Restyled by autopep8

* Update line formatting in TestSpecParsingSupport.py

* Fixed comment on execute_python_tests.py

* tests.yaml test

* Test to fix src/python_testing/test_testing directory imports

* Restyled by isort

* Fixed code lints

* Fix imports for test_testing directory

* Fixed imports on test_TC_ICDM_2_1.py

* Restyled by autopep8

* Restyled by isort

* Updated imported fixes on test_TC_ICDM_2_1.py

* Restyled by autopep8

* Restyled by isort

* Import fixes for parent directory test imports

* Fixing try-except imports for test_testing directory scripts

* Remove unwanted import os from 2 scripts

* Restyled by isort

* Restyled by isort

* Restyled by autopep8

* Restyled by isort

* Updated paths and spec_xml scripts

* Fixed unused imports

* Restyled by isort

* Try to guess data model root

* Fixed wrong string via GUI that was set in vscode

* Fix matter_testing imports

* Comment

* Remove comment

* Fixed import and improved logging via flush of stdout

* Fixed matter support import for test scripts

* Restyled by isort

* Fixed "os.environ is not callable, it is a dictionary"

Co-authored-by: Andrei Litvin <andy314@gmail.com>

* Import fixed for TC_CCTRL_2_3.py

* Update logic to match master

* Fixed multiple executions of the same tests

* Fixed test_testing scripts with master

* Restyled by isort

* Fixing code lints

* Restyled by autopep8

* Fix formate changes happened with autosave on TestSpecParsingSupport.py

* Fixed module import in MockTestRunner script

* Restructured the tasks.py scripts in matter_testing_support

* Fixed formatting

* Restyled by shfmt

* Restyled by isort

* Fixed code lints

* Fixed imports for the new scripts added

* Fixed k1_4 for the test script

* Restyled by autopep8

* Fixed import for new scripts added

* Added support for v1_4

* Update TestSpecParsingSupport.py

* Added the missed part of the code after hard reset from commit d0e3690

* Print statements to test

* Update TestSpecParsingSupport.py

* Added in_progress for DEFAULT_OUTPUT_DIR_IN_PROGRESS

* Added support for conformance_support in atomic attributes

* Removing test prints statements

* Restyled by isort

* Checking in Thermostat's Revision

* Check and Verified Cluster Thermostats's Revision

* Restyled by isort

* Fixed improts with news supports apps.py

* Restyled by isort

* Fixed imports for ECOINFO scripts

* Restyled by isort

* Renamed matter_testing_support to chip.testing

* Update TestSpecParsingSupport.py

* Restyled by shfmt

* Restyled by isort

* Update build_python.sh

* Fix imports for TC_SWITCH.py script

* Restyled by isort

---------

Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Andrei Litvin <andy314@gmail.com>
  • Loading branch information
3 people authored Oct 10, 2024
1 parent afcfba0 commit b1cd9fd
Show file tree
Hide file tree
Showing 203 changed files with 495 additions and 391 deletions.
10 changes: 5 additions & 5 deletions docs/testing/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Python tests located in src/python_testing
section should include various parameters and their respective values,
which will guide the test runner on how to execute the tests.
- All test classes inherit from `MatterBaseTest` in
[matter_testing_support.py](https://github.com/project-chip/connectedhomeip/blob/master/src/python_testing/matter_testing_support.py)
[matter_testing.py](https://github.com/project-chip/connectedhomeip/blob/master/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py)
- Support for commissioning using the python controller
- Default controller (`self.default_controller`) of type `ChipDeviceCtrl`
- `MatterBaseTest` inherits from the Mobly BaseTestClass
Expand All @@ -38,7 +38,7 @@ Python tests located in src/python_testing
decorated with the @async_test_body decorator
- Use `ChipDeviceCtrl` to interact with the DUT
- Controller API is in `ChipDeviceCtrl.py` (see API doc in file)
- Some support methods in `matter_testing_support.py`
- Some support methods in `matter_testing.py`
- Use Mobly assertions for failing tests
- `self.step()` along with a `steps_*` method to mark test plan steps for cert
tests
Expand Down Expand Up @@ -379,7 +379,7 @@ pai = await dev_ctrl.SendCommand(nodeid, 0, Clusters.OperationalCredentials.Comm
## Mobly helpers

The test system is based on Mobly, and the
[matter_testing_support.py](https://github.com/project-chip/connectedhomeip/blob/master/src/python_testing/matter_testing_support.py)
[matter_testing.py](https://github.com/project-chip/connectedhomeip/blob/master/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py)
class provides some helpers for Mobly integration.

- `default_matter_test_main`
Expand Down Expand Up @@ -561,11 +561,11 @@ these steps to set this up:

## Other support utilities

- `basic_composition_support`
- `basic_composition`
- wildcard read, whole device analysis
- `CommissioningFlowBlocks`
- various commissioning support for core tests
- `spec_parsing_support`
- `spec_parsing`
- parsing data model XML into python readable format

# Running tests locally
Expand Down
60 changes: 22 additions & 38 deletions scripts/spec_xml/generate_spec_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,17 @@
from pathlib import Path

import click
from paths import Branch, get_chip_root, get_data_model_path, get_documentation_file_path, get_in_progress_defines

DEFAULT_CHIP_ROOT = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..'))
DEFAULT_OUTPUT_DIR_1_3 = os.path.abspath(
os.path.join(DEFAULT_CHIP_ROOT, 'data_model', '1.3'))
DEFAULT_OUTPUT_DIR_IN_PROGRESS = os.path.abspath(
os.path.join(DEFAULT_CHIP_ROOT, 'data_model', 'in_progress'))
DEFAULT_OUTPUT_DIR_TOT = os.path.abspath(
os.path.join(DEFAULT_CHIP_ROOT, 'data_model', 'master'))
DEFAULT_DOCUMENTATION_FILE = os.path.abspath(
os.path.join(DEFAULT_CHIP_ROOT, 'docs', 'spec_clusters.md'))

# questions
# is energy-calendar still in?
# is heat-pump out? wasn't in 0.7
# location-cluster - is this define gone now?
# queuedpreset - is this define gone now?
CURRENT_IN_PROGRESS_DEFINES = ['aliro', 'atomicwrites', 'battery-storage', 'device-location', 'e2e-jf', 'energy-calendar', 'energy-drlc',
'energy-management', 'heat-pump', 'hrap-1', 'hvac', 'matter-fabric-synchronization', 'metering', 'secondary-net',
'service-area-cluster', 'solar-power', 'tcp', 'water-heater', 'wifiSetup']
# Use the get_in_progress_defines() function to fetch the in-progress defines
CURRENT_IN_PROGRESS_DEFINES = get_in_progress_defines()

# Replace hardcoded paths with dynamic paths using paths.py functions
DEFAULT_CHIP_ROOT = get_chip_root()
DEFAULT_OUTPUT_DIR_1_3 = get_data_model_path(Branch.V1_3)
DEFAULT_OUTPUT_DIR_IN_PROGRESS = get_data_model_path(Branch.IN_PROGRESS)
DEFAULT_OUTPUT_DIR_TOT = get_data_model_path(Branch.MASTER)
DEFAULT_DOCUMENTATION_FILE = get_documentation_file_path()


def get_xml_path(filename, output_dir):
Expand Down Expand Up @@ -90,7 +81,6 @@ def make_asciidoc(target: str, include_in_progress: str, spec_dir: str, dry_run:
'--include-in-progress',
type=click.Choice(['All', 'None', 'Current']), default='All')
def main(scraper, spec_root, output_dir, dry_run, include_in_progress):
# Clusters need to be scraped first because the cluster directory is passed to the device type directory
if not output_dir:
output_dir_map = {'All': DEFAULT_OUTPUT_DIR_TOT, 'None': DEFAULT_OUTPUT_DIR_1_3, 'Current': DEFAULT_OUTPUT_DIR_IN_PROGRESS}
output_dir = output_dir_map[include_in_progress]
Expand All @@ -103,30 +93,28 @@ def main(scraper, spec_root, output_dir, dry_run, include_in_progress):

def scrape_clusters(scraper, spec_root, output_dir, dry_run, include_in_progress):
src_dir = os.path.abspath(os.path.join(spec_root, 'src'))
sdm_clusters_dir = os.path.abspath(
os.path.join(src_dir, 'service_device_management'))
sdm_clusters_dir = os.path.abspath(os.path.join(src_dir, 'service_device_management'))
app_clusters_dir = os.path.abspath(os.path.join(src_dir, 'app_clusters'))
dm_clusters_dir = os.path.abspath(os.path.join(src_dir, 'data_model'))
media_clusters_dir = os.path.abspath(
os.path.join(app_clusters_dir, 'media'))
clusters_output_dir = os.path.abspath(os.path.join(output_dir, 'clusters'))
media_clusters_dir = os.path.abspath(os.path.join(app_clusters_dir, 'media'))

clusters_output_dir = os.path.join(output_dir, 'clusters')

if not os.path.exists(clusters_output_dir):
os.makedirs(clusters_output_dir)

print('Generating main spec to get file include list - this make take a few minutes')
print('Generating main spec to get file include list - this may take a few minutes')
main_out = make_asciidoc('pdf', include_in_progress, spec_root, dry_run)
print('Generating cluster spec to get file include list - this make take a few minutes')
print('Generating cluster spec to get file include list - this may take a few minutes')
cluster_out = make_asciidoc('pdf-appclusters-book', include_in_progress, spec_root, dry_run)

def scrape_cluster(filename: str) -> None:
base = Path(filename).stem
if base not in main_out and base not in cluster_out:
print(f'skipping file: {base} as it is not compiled into the asciidoc')
print(f'Skipping file: {base} as it is not compiled into the asciidoc')
return
xml_path = get_xml_path(filename, clusters_output_dir)
cmd = [scraper, 'cluster', '-i', filename, '-o',
xml_path, '-nd']
cmd = [scraper, 'cluster', '-i', filename, '-o', xml_path, '-nd']
if include_in_progress == 'All':
cmd.extend(['--define', 'in-progress'])
elif include_in_progress == 'Current':
Expand All @@ -150,33 +138,29 @@ def scrape_all_clusters(dir: str, exclude_list: list[str] = []) -> None:
tree = ElementTree.parse(f'{xml_path}')
root = tree.getroot()
cluster = next(root.iter('cluster'))
# If there's no cluster ID table, this isn't a cluster
try:
next(cluster.iter('clusterIds'))
except StopIteration:
# If there's no cluster ID table, this isn't a cluster just some kind of intro adoc
print(f'Removing file {xml_path} as it does not include any cluster definitions')
os.remove(xml_path)
continue


def scrape_device_types(scraper, spec_root, output_dir, dry_run, include_in_progress):
device_type_dir = os.path.abspath(
os.path.join(spec_root, 'src', 'device_types'))
device_types_output_dir = os.path.abspath(
os.path.join(output_dir, 'device_types'))
device_type_dir = os.path.abspath(os.path.join(spec_root, 'src', 'device_types'))
device_types_output_dir = os.path.abspath(os.path.join(output_dir, 'device_types'))
clusters_output_dir = os.path.abspath(os.path.join(output_dir, 'clusters'))

if not os.path.exists(device_types_output_dir):
os.makedirs(device_types_output_dir)

print('Generating device type library to get file include list - this make take a few minutes')
print('Generating device type library to get file include list - this may take a few minutes')
device_type_output = make_asciidoc('pdf-devicelibrary-book', include_in_progress, spec_root, dry_run)

def scrape_device_type(filename: str) -> None:
base = Path(filename).stem
if base not in device_type_output:
print(f'skipping file: {filename} as it is not compiled into the asciidoc')
print(f'Skipping file: {filename} as it is not compiled into the asciidoc')
return
xml_path = get_xml_path(filename, device_types_output_dir)
cmd = [scraper, 'devicetype', '-c', '-cls', clusters_output_dir,
Expand Down
109 changes: 109 additions & 0 deletions scripts/spec_xml/paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#!/usr/bin/env python3

# Copyright (c) 2024 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.

import os
from enum import Enum

# Define a branch enum for different versions or branches


class Branch(Enum):
MASTER = "master"
V1_3 = "v1_3"
V1_4 = "v1_4"
IN_PROGRESS = "in_progress"


def get_chip_root():
"""
Returns the CHIP root directory, trying the environment variable first
and falling back if necessary.
"""
chip_root = os.getenv('PW_PROJECT_ROOT')
if chip_root:
return chip_root
else:
try:
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
except Exception as e:
raise EnvironmentError(
"Unable to determine CHIP root directory. Please ensure the environment is activated."
) from e


def get_data_model_path(branch: Branch):
"""
Returns the path to the data model directory for a given branch.
"""
chip_root = get_chip_root()
data_model_path = os.path.join(chip_root, 'data_model', branch.value)
if not os.path.exists(data_model_path):
raise FileNotFoundError(f"Data model path for branch {branch} does not exist: {data_model_path}")
return data_model_path


def get_spec_xml_output_path():
"""
Returns the path to the output directory for generated XML files.
"""
chip_root = get_chip_root()
output_dir = os.path.join(chip_root, 'out', 'spec_xml')
if not os.path.exists(output_dir):
os.makedirs(output_dir) # Automatically create the directory if it doesn't exist
return output_dir


def get_documentation_file_path():
"""
Returns the path to the documentation file.
"""
chip_root = get_chip_root()
documentation_file = os.path.join(chip_root, 'docs', 'spec_clusters.md')
if not os.path.exists(documentation_file):
raise FileNotFoundError(f"Documentation file does not exist: {documentation_file}")
return documentation_file


def get_python_testing_path():
"""
Returns the path to the python_testing directory.
"""
chip_root = get_chip_root()
python_testing_path = os.path.join(chip_root, 'src', 'python_testing')
if not os.path.exists(python_testing_path):
raise FileNotFoundError(f"Python testing directory does not exist: {python_testing_path}")
return python_testing_path


def get_in_progress_defines():
"""
Returns a list of defines that are currently in progress.
This can be updated dynamically as needed.
"""
return [
'aliro', 'atomicwrites', 'battery-storage', 'device-location', 'e2e-jf',
'energy-calendar', 'energy-drlc', 'energy-management', 'heat-pump', 'hrap-1',
'hvac', 'matter-fabric-synchronization', 'metering', 'secondary-net',
'service-area-cluster', 'solar-power', 'tcp', 'water-heater', 'wifiSetup'
]


def get_available_branches():
"""
Return a list of available branches for the data model.
This can be expanded or dynamically fetched if necessary.
"""
return [Branch.MASTER, Branch.V1_3, Branch.V1_4]
6 changes: 3 additions & 3 deletions src/python_testing/MinimalRepresentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@

from dataclasses import dataclass, field

from chip.testing.conformance import ConformanceDecision
from chip.testing.global_attribute_ids import GlobalAttributeIds
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
from chip.tlv import uint
from conformance_support import ConformanceDecision
from global_attribute_ids import GlobalAttributeIds
from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main
from TC_DeviceConformance import DeviceConformanceTests


Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TCP_Tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import chip.clusters as Clusters
from chip import ChipDeviceCtrl
from chip.interaction_model import InteractionModelError
from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
from mobly import asserts


Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_ACE_1_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from chip.clusters.Attribute import EventReadResult, SubscriptionTransaction, TypedAttributePath
from chip.exceptions import ChipStackError
from chip.interaction_model import Status
from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
from mobly import asserts


Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_ACE_1_3.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

import chip.clusters as Clusters
from chip.interaction_model import Status
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from mobly import asserts


Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_ACE_1_4.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

import chip.clusters as Clusters
from chip.interaction_model import Status
from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
from mobly import asserts

# This test requires several additional command line arguments
Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_ACE_1_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import chip.clusters as Clusters
from chip import ChipDeviceCtrl
from chip.interaction_model import Status
from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
from mobly import asserts


Expand Down
4 changes: 2 additions & 2 deletions src/python_testing/TC_ACL_2_11.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@
import queue

import chip.clusters as Clusters
from basic_composition_support import arls_populated
from chip.clusters.Attribute import EventReadResult, SubscriptionTransaction, ValueDecodeFailure
from chip.clusters.ClusterObjects import ALL_ACCEPTED_COMMANDS, ALL_ATTRIBUTES, ALL_CLUSTERS, ClusterEvent
from chip.clusters.Objects import AccessControl
from chip.clusters.Types import NullValue
from chip.interaction_model import InteractionModelError, Status
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from chip.testing.basic_composition import arls_populated
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from mobly import asserts


Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_ACL_2_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
# === END CI TEST ARGUMENTS ===

import chip.clusters as Clusters
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from mobly import asserts


Expand Down
10 changes: 5 additions & 5 deletions src/python_testing/TC_AccessChecker.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
from typing import Optional

import chip.clusters as Clusters
from basic_composition_support import BasicCompositionTests
from chip.interaction_model import Status
from chip.testing.basic_composition import BasicCompositionTests
from chip.testing.global_attribute_ids import GlobalAttributeIds
from chip.testing.matter_testing import (AttributePathLocation, ClusterPathLocation, MatterBaseTest, TestStep, async_test_body,
default_matter_test_main)
from chip.testing.spec_parsing import XmlCluster, build_xml_clusters
from chip.tlv import uint
from global_attribute_ids import GlobalAttributeIds
from matter_testing_support import (AttributePathLocation, ClusterPathLocation, MatterBaseTest, TestStep, async_test_body,
default_matter_test_main)
from spec_parsing_support import XmlCluster, build_xml_clusters


class AccessTestType(Enum):
Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_BOOLCFG_2_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from operator import ior

import chip.clusters as Clusters
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from mobly import asserts


Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_BOOLCFG_3_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

import chip.clusters as Clusters
from chip.interaction_model import Status
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
from mobly import asserts


Expand Down
Loading

0 comments on commit b1cd9fd

Please sign in to comment.