Skip to content

Commit

Permalink
Docs: Start of testing documentation
Browse files Browse the repository at this point in the history
Pulls from the test harness presentations in Korea and Geneva
  • Loading branch information
cecille committed Jan 20, 2024
1 parent 373f45e commit bca5a7b
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ cluster_and_device_type_dev/index
guides/index
style/index
examples/index
testing/index
tools/index
BUG_REPORT
code_generation
Expand Down
5 changes: 5 additions & 0 deletions docs/testing/ci_testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# CI testing

This file is a placeholder for information on how to run tests in the CI.

NOTE: discuss in particular triggers direct to the device, test event triggers and the CI pics.
26 changes: 26 additions & 0 deletions docs/testing/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Testing Guides

The following guide provide an introduction to the testing mechanisms available in the SDK.

```{toctree}
:glob:
:maxdepth: 1
:hidden:
*
```

## Unit testing
- [Unit tests](./unit_testing.md)

## Integration and Certification tests
- [Integration and Certification tests](./integration_tests.md)
- [YAML](./yaml.md)
- [Python testing framework](./python.md)
- [Enabling tests in the CI](./ci_testing.md)

## PICS and PIXIT
- [PICS and PIXIT](./pics_and_pixit.md)

## Testing in the CI
- [CI testing](./ci_testing.md)
24 changes: 24 additions & 0 deletions docs/testing/integration_tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Integration and Certification Tests

Integration tests use a server and a controller or controllers to test the behavior of a device. Certification tests are all integration tests. For certified products, the device under test (DUT) is tested against one of the SDK controller implementations (either chip-tool or the python-based controller, depending on the test type). For software component certification, the software component is tested against a sample device built from the SDK.

Certification tests require an accompanying certification test plan in order to be used in the certification testing process. More information about test plans can be found in the [test plans repository](https://github.com/CHIP-Specifications/chip-test-plans/tree/master/docs). Integration testing can also be used outside of the certification testing program to test device behavior in the SDK. Certification tests are all run in the [CI](./ci_testing).

There are two main integration test types:

- [YAML](./yaml.md)
- [Python framework](./python.md)

YAML is a human-readable serialization language that uses structured tags to define test steps. Tests are defined in YAML, and parsed and run through a runner that is backed by the chip-tool controller.

The Python framework tests are written in python and use the [Mobly](https://github.com/google/mobly) test framework to execute tests.

## Which test framework to use
Both types of tests can be run through the Test Harness for certification testing, locally for the purposes of development and in the CI for the SDK. The appropriate test framework to use is whatever lets you automate your tests in a way that is understandable, readable, and has the features you need

* YAML
* pros: more readable, simpler to write, easy for ATLs to parse and understand
* cons: conditionals are harder (not all supported), no branch control, schema not well documented
* python
* pros: full programming language, full control API with support for core (certs, commissioning, etc), less plumbing if you need to add features, can use python libs
* cons: more complex, can be harder to read
Empty file added docs/testing/python.md
Empty file.
Empty file added docs/testing/unit_testing.md
Empty file.
282 changes: 282 additions & 0 deletions docs/testing/yaml.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
# YAML tests

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](./yaml_schema.md)

## Writing YAML tests

Most YAML tests are written for certification. These follow a standard format that is used to display the test easily in the test harness.

### Placeholder for anatomy of a yaml test - need diagram

### Placeholder for anatomy of a test step - need diagram

### Common actions
#### Sending a cluster command
The following shows a test step sending a simple command with no arguments.
```
- label: "This label gets printed"
cluster: "On/Off"
command: "On"
```
* label - label to print before performing the test step
* cluster - name of the cluster to send the command to
* command - name of the command to send

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
```
* label - label to print before performing the test step
* command - name of the command to send
* argument - this is a list parameter that takes either a "value" or "values" tag. Commands with arguments all use structured fields, which require the "values" tag with a list. Each of the fields is represented by a "name" and "value" pair

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

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
```

#### Parsing Responses
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:<br />&emsp;value: [1, 2, 3, 4] | must match exactly. Variables and saveAs values allowed |
| response:<br />&emsp;values:<br />&emsp;&emsp;- name: response_field<br />&emsp;&emsp;&nbsp;&nbsp; value: 1 | Must match exactly<br />Use for commands that return command responses with named fields |
| response:<br /> &emsp; error: CONSTRAINT_ERROR | expect an error back (omit for success)<br />Variables and saveAs values will not work. |
| response:<br />&emsp;constraints: | more complex checks - see [Schema](./yaml_schema.md) for a complete description |


#### Lists and structs

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.



#### Pseudo clusters
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 psudo-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 below:

TODO: generate a script to parse the pseudo cluster xml into something readable


#### Config variables and saveAs:
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](./yaml_schema.md).


Config variables can be used to implement PIXIT values in tests.

#### Gating tests and steps: PICS, TestEqualities and runIf
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](https://github.com/project-chip/connectedhomeip/blob/master/src/app/tests/suites/TestEqualities.yaml) for an example of how to use this pseudo-cluster.

## Running YAML tests
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).

### Running locally
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.

```
./scripts/build_python.sh -i py
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](https://github.com/project-chip/connectedhomeip/blob/master/scripts/tests/yaml/chiptool.py) can be used to run tests against a commissioned DUT (commissioned by chip-tool). This will start an interactive instance of chip-tool automatically.

```
./scripts/tests/yaml/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/yaml/chiptool.py list
```

Config variables can be passed to chiptool.py after the script by separating with --

```
./scripts/tests/yaml/chiptool.py tests Test_TC_OO_2_1 --server_path ./out/linux-x64-chip-tool/chip-tool -- nodeId 0x12344321
```

### Running in the CI

* YAML tests added to the certification directory get run automatically
* src/app/tests/suites/certification/
* PICS file: src/app/tests/suites/certification/ci-pics-values
* If you DON’T want to run a test in the CI
* (ex under development), add it to _GetInDevelopmentTests in scripts/tests/chiptest/__init__.py

### Running in the TH

TODO: Do we have a permanent link to the most up to date TH documentation? If so, add here.

0 comments on commit bca5a7b

Please sign in to comment.