YAML is a structured, human-readable data-serialization language. Much like json or proto, YAML refers to the structure and parser, and the schema used for any particular application is defined by the application.
In Matter, we use YAML for describing tests and test steps. A YAML parser and runner is then used to translate the YAML instructions into actions used to interact with the device under test (DUT).
The main runner we use for testing in Matter parses the YAML instructions into chip-tool commands.
The schema description for the Matter test YAML is available here: YAML Schema
Most YAML tests are written for certification. These follow a standard format that is used to display the test easily in the test harness.
The following shows a test step sending a simple command with no arguments.
- label: "This label gets printed" cluster: "On/Off" command: "On"
This send the On command to the On/Off cluster on the DUT. For most tests, the nodeID of the DUT and endpoint for the cluster are defined in the top-level config section of the file and applied to every test step. However, these can also be overwritten in the individual test steps.
The following shows how to send a command with arguments:
- label: "This label gets printed before the test step" command: "MoveToColor" arguments: values: - name: "ColorX" value: 32768 - name: "ColorY" value: 19660 - name: "TransitionTime" value: 0 - name: "OptionsMask" value: 0 - name: "OptionsOverride" value: 0
In this command, the cluster: tag is elided. The cluster for the entire test can be set in the config section at the top of the test. This can be overwritten for individual test steps (as above).
Reading and writing attributes is represented in the Matter test YAML schemas as a special command that requires an additional “attribute” tag.
The following YAML would appear as a test step, and shows how to read an attribute.
- label: "TH reads the ClusterRevision from DUT" command: "readAttribute" attribute: "ClusterRevision"
The following YAML would appear as a test step and shows how to write an attribute. Commands to write attributes always require an argument: tag.
- label: "Write example attribute" command: "writeAttribute" attribute: "ExampleAttribute" arguments: value: 1
After sending a command or read or write attribute request, you may want to verify the response. This is done using the “response” tag with various sub-tags.
The following shows a simple response parsing with two (somewhat redundant) checks.
- label: "TH reads the ClusterRevision from DUT" command: "readAttribute" attribute: "ClusterRevision" response: value: 1 constraints: minValue: 1
The following tags can be used to parse the response
Example | Description |
---|---|
response: value: [1, 2, 3, 4] | must match exactly. Variables and saveAs values allowed |
response: values: - name: response_field value: 1 | Must match exactly Use for commands that return command responses with named fields |
response: error: CONSTRAINT_ERROR | expect an error back (omit for success) Variables and saveAs values will not work. |
response: constraints: | more complex checks - see Schema for a complete description |
Lists and structs can be represented as follows:
Lists: [1,2,3,4,5]
structs: {field1:value, field2:value}
lists of structs:
[ {field1:value, field2:value, optionalfield:value}, {field1:value, field2:value}, ]
Note that structs are different than command and command response fields, which are represented using name:, value: tags.
Tests often require functionality that is not strictly cluster-based. Some of this functionality is supported in YAML using pseudo-clusters. These clusters accept command: tags like the DUT clusters to control the pseudo-cluster functionality.
Some of the more common functionality is shown below:
Establishing a connection to the DUT. This is the first step in nearly every test.
- label: "Establish a connection to the DUT" cluster: "DelayCommands" command: "WaitForCommissionee" arguments: values: - name: "nodeId" value: nodeId
Wait for a user action:
- label: "Do a simple user prompt message. Expect 'y' to pass." cluster: "LogCommands" command: "UserPrompt" arguments: values: - name: "message" value: "Please enter 'y' for success" - name: "expectedValue" value: "y"
Wait for a time:
- label: "Wait for 5S" cluster: "DelayCommands" command: "WaitForMs" arguments: values: - name: "ms" value: 5000
A full description of the available pseudo-clusters and their commands is available at Pseudo-cluster description.
Certain tags can use variables that are either declared in the config: section or saved from other steps. Variables that are declared in the config can be overwritten on the command line when running locally or through the config file in the test harness.
To declare config variables in the config section, use a label with the desired name, then provide the type and defaultValue tags as sub-tags.
config: nodeId: 0x12344321 cluster: "Unit Testing" endpoint: 1 myArg1: type: int8u defaultValue: 5
Variables can also be saved from responses:
- label: "Send Test Add Arguments Command" command: "TestAddArguments" arguments: values: - name: "arg1" value: 3 - name: "arg2" value: 17 response: values: - name: "returnValue" saveAs: TestAddArgumentDefaultValue value: 20
Variables can then be used in later steps:
- label: "Send Test Add Arguments Command" command: "TestAddArguments" arguments: values: - name: "arg1" value: 3 - name: "arg2" value: 17 response: values: - name: "returnValue" value: TestAddArgumentDefaultValue
Tags where variables can be used are noted in the schema description.
Config variables can be used to implement PIXIT values in tests.
The PICS tag can be used to unconditionally gate a test step on the PICS value in the file.
The PICS tag can handle standard boolean operations on pics (!, ||, &&, ()).
A PICS tag at the top level of the file can be used to gate the entire test in the test harness. Note that full-test gating is not currently implemented in the local runner or in the CI.
Some test steps need to be gated on values from earlier in the test. In these cases, PICS cannot be used. Instead, the runIf: tag can be used. This tag requires a boolean value. To convert values to booleans, the TestEqualities function can be use. See TestEqualities for an example of how to use this pseudo-cluster.
The timeout argument can be used for each individual test step to set the time the runner will wait for a test step to complete before reporting a failure.
Note that this timeout is different than the subscription report timeout and the subscription report timeout is not currently adjustable in YAML.
There several other options for configuring test steps as shown in the YAML schema document.
YAML scripts are parsed and run using a python-based runner program that parses the file, then translates the tags into chip-tool commands, and sends those commands over a socket to chip-tool (running in interactive mode).
All YAML tests assume that the DUT has previously been commissioned before running. DUTs should be commissioned using chip-tool. Use the same KVS file when running the test.
By default, the tests use node ID 0x12344321. The easiest way to run the tests is to commission with this node ID. Alternately, you can change the target node ID on the command line, as shown in the Running the tests section.
There are several options for running tests locally. Because the YAML runner uses python, it is necessary to compile and install the chip python package before using any YAML runner script.
First activate the matter environment using either
. ./scripts/bootstrap.sh
or
. ./scripts/activate.sh
bootstrap.sh should be used for for the first setup, activate.sh may be used for subsequent setups as it is faster.
Next build the python wheels and create a venv (called py
here, but any name may be used)
./scripts/build_python.sh -i out/python_env source py/bin/activate
Compile chip-tool:
./scripts/build/build_examples.py --target linux-x64-chip-tool build
NOTE: use the target appropriate to your system
chiptool.py can be used to run tests against a commissioned DUT (commissioned by chip-tool). To commission a DUT using chip-tool use the pairing command. For example:
./out/linux-x64-chip-tool/chip-tool pairing code 0x12344321 MT:-24J0AFN00KA0648G00
In this example, 0x12344321 is the node ID (0x12344321 is the test default) and MT:-24J0AFN00KA0648G00 is the QR code.
The chiptool.py tool can then be used to run the tests. For example:
./scripts/tests/chipyaml/chiptool.py tests Test_TC_OO_2_1 --server_path ./out/linux-x64-chip-tool/chip-tool
NOTE: substitute the appropriate test name and chip-tool path as appropriate.
A list of available tests can be generated using:
./scripts/tests/chipyaml/chiptool.py list
Config variables can be passed to chiptool.py after the script by separating with --
./scripts/tests/chipyaml/chiptool.py tests Test_TC_OO_2_1 --server_path ./out/linux-x64-chip-tool/chip-tool -- nodeId 0x12344321
Each test defines a default endpoint to target. Root node cluster tests run against endpoint 0 by default. Most other cluster tests run against endpoint 1. You can set the endpoint for the test using the endpoint
config variable.
On the host machine, you can simulate a factory reset by deleting the KVS file. If you did not specify a location for the KVS file when starting the application, the KVS file will be in /tmp as chip_kvs
scripts/tests/chiptest/__init__.py
Please see CI testing for more information about how to set up examples apps, PICS and PIXIT values for use in the CI.
TODO: Do we have a permanent link to the most up to date TH documentation? If so, add here.