| #!/usr/bin/env -S python3 -B |
| |
| # 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. |
| |
| import logging |
| import os |
| import queue |
| import re |
| import shlex |
| import signal |
| import subprocess |
| import sys |
| |
| import click |
| import coloredlogs |
| from colorama import Fore, Style |
| from java.base import DumpProgramOutputToQueue |
| from java.commissioning_test import CommissioningTest |
| from java.im_test import IMTest |
| |
| |
| @click.command() |
| @click.option("--app", type=click.Path(exists=True), default=None, |
| help='Path to local application to use, omit to use external apps.') |
| @click.option("--app-args", type=str, default='', |
| help='The extra arguments passed to the device.') |
| @click.option("--tool-path", type=click.Path(exists=True), default=None, |
| help='Path to java-matter-controller.') |
| @click.option("--tool-cluster", type=str, default='pairing', |
| help='The cluster name passed to the java-matter-controller.') |
| @click.option("--tool-args", type=str, default='', |
| help='The arguments passed to the java-matter-controller.') |
| @click.option("--factoryreset", is_flag=True, |
| help='Remove app configs (/tmp/chip*) before running the tests.') |
| def main(app: str, app_args: str, tool_path: str, tool_cluster: str, tool_args: str, factoryreset: bool): |
| logging.info("Execute: {script_command}") |
| |
| if factoryreset: |
| # Remove native app config |
| retcode = subprocess.call("rm -rf /tmp/chip*", shell=True) |
| if retcode != 0: |
| raise Exception("Failed to remove /tmp/chip* for factory reset.") |
| |
| print("Contents of test directory: %s" % os.getcwd()) |
| print(subprocess.check_output(["ls -l"], shell=True).decode('utf-8')) |
| |
| # Remove native app KVS if that was used |
| kvs_match = re.search(r"--KVS (?P<kvs_path>[^ ]+)", app_args) |
| if kvs_match: |
| kvs_path_to_remove = kvs_match.group("kvs_path") |
| retcode = subprocess.call("rm -f %s" % kvs_path_to_remove, shell=True) |
| print("Trying to remove KVS path %s" % kvs_path_to_remove) |
| if retcode != 0: |
| raise Exception("Failed to remove %s for factory reset." % kvs_path_to_remove) |
| |
| coloredlogs.install(level='INFO') |
| |
| log_queue = queue.Queue() |
| log_cooking_threads = [] |
| |
| if tool_path: |
| if not os.path.exists(tool_path): |
| if tool_path is None: |
| raise FileNotFoundError(f"{tool_path} not found") |
| |
| app_process = None |
| if app: |
| if not os.path.exists(app): |
| if app is None: |
| raise FileNotFoundError(f"{app} not found") |
| app_args = [app] + shlex.split(app_args) |
| logging.info(f"Execute: {app_args}") |
| app_process = subprocess.Popen( |
| app_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0) |
| DumpProgramOutputToQueue( |
| log_cooking_threads, Fore.GREEN + "APP " + Style.RESET_ALL, app_process, log_queue) |
| |
| command = ['java', |
| f'-Djava.library.path={tool_path}/lib/jni', |
| '-cp', |
| ':'.join([ |
| f'{tool_path}/lib/*', |
| f'{tool_path}/lib/third_party/connectedhomeip/src/controller/java/*', |
| f'{tool_path}/bin/kotlin-matter-controller', |
| ]), |
| 'com.matter.controller.MainKt'] |
| |
| if tool_cluster == 'pairing': |
| logging.info("Testing pairing") |
| |
| test = CommissioningTest(log_cooking_threads, log_queue, command, tool_args) |
| try: |
| test.RunTest() |
| except Exception as e: |
| logging.error(e) |
| sys.exit(1) |
| elif tool_cluster == 'im': |
| logging.info("Testing IM") |
| |
| test = IMTest(log_cooking_threads, log_queue, command, tool_args) |
| try: |
| test.RunTest() |
| except Exception as e: |
| logging.error(e) |
| sys.exit(1) |
| |
| app_exit_code = 0 |
| if app_process: |
| logging.warning("Stopping app with SIGINT") |
| app_process.send_signal(signal.SIGINT.value) |
| app_exit_code = app_process.wait() |
| |
| # There are some logs not cooked, so we wait until we have processed all logs. |
| # This procedure should be very fast since the related processes are finished. |
| for thread in log_cooking_threads: |
| thread.join() |
| |
| # We expect app should exit with 0 |
| sys.exit(app_exit_code) |
| |
| |
| if __name__ == '__main__': |
| main() |