| # 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 libraries |
| - cons: more complex, can be harder to read |
| |
| ## Running integration tests locally |
| |
| ### Application and tool binary path selection in the YAML test framework |
| |
| The `scripts/tests/run_test_suite.py` script is used to run the YAML tests |
| locally. Apart from the YAML files describing particular test cases the script |
| also needs information about the locations of the application (for example |
| `chip-all-clusters`) and tool (for example `chip-tool`) binaries. This |
| information is provided via `--app-path` and `--tool-path` commandline switches. |
| As an example: |
| |
| ```shell |
| scripts/tests/run_test_suite.py --runner chip_tool_python \ |
| run \ |
| --tool-path chip-tool:out/linux-x64-chip-tool/chip-tool \ |
| --app-path all-clusters:out/linux-x64-all-clusters/chip-all-clusters-app |
| ``` |
| |
| The distinction between applications and tools is not merely cosmetic. It is |
| used when running tests in Linux network namespaces to place applications and |
| tools in separate network namespaces. |
| |
| In order to help with using the YAML tests for local usage the |
| `--discover-paths` flag can be used to automatically discover paths to |
| applications and tools. The root directory of the Matter SDK is used as the |
| starting path of the search. |
| |
| You can also list the known keys for applications and tools by using the |
| `--help-paths` option: |
| |
| ```shell |
| scripts/tests/run_test_suite.py run --help-paths |
| … |
| --- |
| # Known application and tool path keys: |
| - key: all-clusters |
| kind: app |
| - key: all-devices |
| kind: app |
| - key: air-purifier |
| kind: app |
| - key: bridge |
| kind: app |
| - key: camera |
| kind: app |
| - key: camera-controller |
| kind: app |
| - key: closure |
| kind: app |
| - key: energy-gateway |
| kind: app |
| - key: evse |
| kind: app |
| - key: water-heater |
| kind: app |
| - key: fabric-bridge |
| kind: app |
| - key: fabric-admin |
| kind: app |
| - key: fabric-sync |
| kind: app |
| … |
| ``` |
| |
| ## Connectivity mocking for local testing |
| |
| When integration tests are run locally, the test runner (YAML or python) needs |
| to mock network connectivity between the controller and the device under test, |
| so that all tests can be run without actual hardware. In case of a simple test |
| case when a single device is tested with on-network commissioning, nothing |
| special is needed - the controller can connect to the device directly over the |
| local (loopback) network interface. However, for more complex test cases that |
| involve multiple devices or other than on-network commissioning (e.g. ble-wifi |
| or ble-thread), some additional setup is needed. |
| |
| ### Running tests in Linux network namespaces |
| |
| The test suite on Linux uses user namespaces (`unshare --map-root-user`) to |
| create these isolated network environments. On some systems, this feature might |
| be disabled by default. To enable it, ensure the following lines are present in |
| `/etc/sysctl.conf` or a new file under `/etc/sysctl.d/`: |
| |
| ``` |
| kernel.unprivileged_userns_clone = 1 |
| ``` |
| |
| On systems with AppArmor (like Ubuntu), you also need: |
| |
| ``` |
| kernel.apparmor_restrict_unprivileged_userns = 0 |
| ``` |
| |
| After adding these lines, apply the changes by running `sudo sysctl --system`. |
| |
| The simplest way to mock more complex network topologies is to use Linux network |
| namespaces. Each device (controller or DUT) is run in its own network namespace, |
| which allows them to have their own network interfaces and corresponding IP |
| addresses. |
| |
| For convenience, there is a script that can set up network namespaces and run a |
| test case in them: |
| |
| ```shell |
| # Build the chip-tool and chip-all-clusters-app if not done already |
| scripts/build/build_examples.py --target linux-x64-chip-tool --target linux-x64-all-clusters build |
| # Run the TestOperationalState test case in the Linux network namespaces |
| scripts/tests/run_test_suite.py --runner chip_tool_python \ |
| --target TestOperationalState \ |
| --log-level=debug \ |
| run \ |
| --app-path all-clusters:out/linux-x64-all-clusters/chip-all-clusters-app \ |
| --tool-path chip-tool:out/linux-x64-chip-tool/chip-tool |
| ``` |
| |
| ### Running tests with mocked BLE and Wi-Fi connectivity |
| |
| For more complex commissioning flows that involve BLE and Wi-Fi, the test runner |
| needs to mock BLE and Wi-Fi connectivity as well. On Linux, BLE and Wi-Fi are |
| provided by the BlueZ stack and WPA supplicant, respectively. The SDK uses D-Bus |
| to interact with these services. This allows the test runner to mock BLE and |
| Wi-Fi connectivity by simply mocking used D-Bus APIs of these services. |
| |
| Additionally, the Matter specification forbids device to advertise on more than |
| one network type at a time, so in case of ble-wifi commissioning, the DUT shall |
| not be accessible over Wi-Fi until it is commissioned. This can be achieved by |
| using Linux network namespaces as described above, but instead of setting up |
| network interfaces before commissioning, the test runner assigns IP address to |
| the DUT's network interface only after mock Wi-Fi connection is associated. |
| |
| See the diagram below for an overview of the setup: |
| |
| ```mermaid |
| flowchart TD |
| |
| subgraph Mocked BlueZ |
| BA1[adapter1<br>00:00:00:11:11:11] |
| BA2[adapter2<br>00:00:00:22:22:22] |
| end |
| |
| subgraph Mocked WPA supplicant |
| WL0[wlan0] |
| end |
| |
| subgraph Test D-Bus system bus |
| direction TB |
| org.bluez.hci0[org.bluez.Adapter<br>hci0] |
| org.bluez.hci1[org.bluez.Adapter<br>hci1] |
| fi.w1[fi.w1.wpa_supplicant1.Interface<br>wlan0] |
| end |
| |
| BA1 --- org.bluez.hci0 |
| BA2 --- org.bluez.hci1 |
| WL0 --- fi.w1 |
| |
| subgraph ETH["TOOL network namespace"] |
| CONTROLLER[chip-tool] |
| ETH0[eth0<br>fd00:0:1:1::2] |
| end |
| |
| subgraph WLAN["DUT network namespace"] |
| DUT[chip-all-clusters-app] |
| WLAN0[wlan0<br>not assigned] |
| end |
| |
| fi.w1 --- DUT |
| org.bluez.hci0 --- DUT |
| org.bluez.hci1 --- CONTROLLER |
| |
| ``` |
| |
| In order to run tests with mocked BLE and Wi-Fi connectivity and Linux network |
| namespaces use the `--commissioning-method ble-wifi` option to the `run` command |
| of the `scripts/tests/run_test_suite.py` script: |
| |
| ```shell |
| # Run the TestOperationalState test case with ble-wifi commissioning |
| scripts/tests/run_test_suite.py --runner chip_tool_python \ |
| --target TestOperationalState \ |
| --log-level=debug \ |
| run \ |
| --app-path all-clusters:out/linux-x64-all-clusters/chip-all-clusters-app \ |
| --tool-path chip-tool:out/linux-x64-chip-tool/chip-tool \ |
| --commissioning-method ble-wifi |
| ``` |