diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 929cd16..7d9641a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,7 +2,7 @@ // README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile { "name": "dev", - "image": "ghcr.io/ten-framework/ten_agent_build:0.3.3", + "image": "ghcr.io/ten-framework/ten_agent_build:0.3.5", "customizations": { "vscode": { "extensions": [ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97d84e5..2d80597 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: ci: runs-on: ubuntu-latest container: - image: ghcr.io/ten-framework/ten_agent_build:0.3.3 + image: ghcr.io/ten-framework/ten_agent_build:0.3.5 steps: - uses: actions/checkout@v4 with: @@ -34,7 +34,10 @@ jobs: - name: Check ten dependencies run: | task install - task test + + - name: Run tests + run: | + task test -- -s -v - name: Release if: startsWith(github.ref, 'refs/tags/') diff --git a/tests/bin/start b/tests/bin/start index ca5fbbd..b3d73dd 100755 --- a/tests/bin/start +++ b/tests/bin/start @@ -5,6 +5,7 @@ set -e cd "$(dirname "${BASH_SOURCE[0]}")/../.." export PYTHONPATH=.ten/app/ten_packages/system/ten_runtime_python/lib:.ten/app/ten_packages/system/ten_runtime_python/interface +export TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE=true # If the Python app imports some modules that are compiled with a different # version of libstdc++ (ex: PyTorch), the Python app may encounter confusing @@ -18,4 +19,4 @@ export PYTHONPATH=.ten/app/ten_packages/system/ten_runtime_python/lib:.ten/app/t # # Refer to https://github.com/pytorch/pytorch/issues/102360?from_wecom=1#issuecomment-1708989096 -pytest -s tests/ "$@" +pytest tests/ "$@" diff --git a/tests/test_invalid_path.py b/tests/test_404.py similarity index 62% rename from tests/test_invalid_path.py rename to tests/test_404.py index 8219e8b..1730fe5 100644 --- a/tests/test_invalid_path.py +++ b/tests/test_404.py @@ -17,7 +17,7 @@ import httpx -class ExtensionTesterInvalidPathCase1(ExtensionTester): +class ExtensionTesterNotFound1(ExtensionTester): def on_start(self, ten_env: TenEnvTester) -> None: ten_env.on_start_done() @@ -28,7 +28,7 @@ def on_start(self, ten_env: TenEnvTester) -> None: ten_env.stop_test() -class ExtensionTesterInvalidPathCase2(ExtensionTester): +class ExtensionTesterNotFound2(ExtensionTester): def on_start(self, ten_env: TenEnvTester) -> None: ten_env.on_start_done() @@ -39,14 +39,13 @@ def on_start(self, ten_env: TenEnvTester) -> None: ten_env.stop_test() -# TODO: disable it currently since second tester seems can not run. enable it once fixed -# def test_invalid_path(): -# tester = ExtensionTesterInvalidPathCase1() -# tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) -# tester.set_test_mode_single("http_server_python") -# tester.run() +def test_404(): + tester = ExtensionTesterNotFound1() + tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) + tester.set_test_mode_single("http_server_python") + tester.run() -# tester2 = ExtensionTesterInvalidPathCase2() -# tester2.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) -# tester2.set_test_mode_single("http_server_python") -# tester2.run() + tester2 = ExtensionTesterNotFound2() + tester2.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) + tester2.set_test_mode_single("http_server_python") + tester2.run() diff --git a/tests/test_5xx.py b/tests/test_5xx.py new file mode 100644 index 0000000..d7b4433 --- /dev/null +++ b/tests/test_5xx.py @@ -0,0 +1,60 @@ +# +# Copyright © 2025 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +from pathlib import Path +from typing import Optional +from ten import ( + ExtensionTester, + TenEnvTester, + Cmd, + CmdResult, + StatusCode, + TenError, +) +import httpx +import threading + + +class ExtensionTester5xx(ExtensionTester): + def __init__(self): + super().__init__() + self.thread = None + self.event = threading.Event() + + def on_cmd(self, ten_env: TenEnvTester, cmd: Cmd) -> None: + print(f"on_cmd name {cmd.get_name()}") + ten_env.return_result(CmdResult.create(StatusCode.ERROR), cmd) + + event_got = self.event.wait(timeout=5) + if not event_got: # timeout + print("test error") + else: + ten_env.stop_test() + + def on_start(self, ten_env: TenEnvTester) -> None: + + self.thread = threading.Thread(target=self._async_request, args=[]) + self.thread.start() + + ten_env.on_start_done() + + def _async_request(self) -> None: + property_json = {"num": 1, "str": "111"} + r = httpx.post("http://127.0.0.1:8888/cmd/abc", + json=property_json, timeout=5) + print(r) + + if r.status_code >= 500: + # TODO: stop test directly once albe to call it in separate thread + # ten_env.stop_test() + self.event.set() + + +def test_5xx(): + tester = ExtensionTester5xx() + tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) + tester.set_test_mode_single("http_server_python") + tester.run() diff --git a/tests/test_basic.py b/tests/test_basic.py new file mode 100644 index 0000000..a0153ef --- /dev/null +++ b/tests/test_basic.py @@ -0,0 +1,58 @@ +# +# Copyright © 2025 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +from pathlib import Path +from ten import ( + ExtensionTester, + TenEnvTester, + Cmd, + CmdResult, + StatusCode, +) +import httpx +import threading + + +class ExtensionTesterBasic(ExtensionTester): + def __init__(self): + super().__init__() + self.thread = None + self.event = threading.Event() + + def on_cmd(self, ten_env: TenEnvTester, cmd: Cmd) -> None: + print(f"on_cmd name {cmd.get_name()}") + ten_env.return_result(CmdResult.create(StatusCode.OK), cmd) + + event_got = self.event.wait(timeout=5) + if not event_got: # timeout + print("test error") + else: + ten_env.stop_test() + + def on_start(self, ten_env: TenEnvTester) -> None: + + self.thread = threading.Thread(target=self._async_request, args=[]) + self.thread.start() + + ten_env.on_start_done() + + def _async_request(self) -> None: + property_json = {"num": 1, "str": "111"} + r = httpx.post("http://127.0.0.1:8888/cmd/abc", + json=property_json, timeout=5) + print(r) + + if r.status_code == httpx.codes.OK: + # TODO: stop test directly once albe to call it in separate thread + # ten_env.stop_test() + self.event.set() + + +def test_basic(): + tester = ExtensionTesterBasic() + tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) + tester.set_test_mode_single("http_server_python") + tester.run() diff --git a/tests/test_set_property.py b/tests/test_set_property.py new file mode 100644 index 0000000..34a3fbb --- /dev/null +++ b/tests/test_set_property.py @@ -0,0 +1,75 @@ +# +# Copyright © 2025 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +from pathlib import Path +from ten import ( + ExtensionTester, + TenEnvTester, + Cmd, + CmdResult, + StatusCode, +) +import httpx +import threading + + +class ExtensionTesterSetProperty(ExtensionTester): + def __init__(self): + super().__init__() + self.thread = None + self.event = threading.Event() + + def on_cmd(self, ten_env: TenEnvTester, cmd: Cmd) -> None: + print(f"on_cmd name {cmd.get_name()}") + ten_env.return_result(CmdResult.create(StatusCode.OK), cmd) + + event_got = self.event.wait(timeout=5) + if not event_got: # timeout + print("test error") + else: + ten_env.stop_test() + + def on_start(self, ten_env: TenEnvTester) -> None: + + self.thread = threading.Thread(target=self._async_request, args=[]) + self.thread.start() + + ten_env.on_start_done() + + def _async_request(self) -> None: + property_json = {"num": 1, "str": "111"} + r = httpx.post("http://127.0.0.1:8899/cmd/abc", + json=property_json, timeout=5) + print(r) + + if r.status_code == httpx.codes.OK: + # TODO: stop test directly once albe to call it in separate thread + # ten_env.stop_test() + self.event.set() + + +def test_set_property(): + + # change port + property_json_1 = '{"listen_port":8899}' + tester_1 = ExtensionTesterSetProperty() + tester_1.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) + tester_1.set_test_mode_single("http_server_python", property_json_1) + tester_1.run() + + # change port with localhost + property_json_2 = '{"listen_addr":"127.0.0.1","listen_port":8899}' + tester_2 = ExtensionTesterSetProperty() + tester_2.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) + tester_2.set_test_mode_single("http_server_python", property_json_2) + tester_2.run() + + # change port with any addr + property_json_3 = '{"listen_addr":"0.0.0.0","listen_port":8899}' + tester_3 = ExtensionTesterSetProperty() + tester_3.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) + tester_3.set_test_mode_single("http_server_python", property_json_3) + tester_3.run() diff --git a/tests/test_timeout.py b/tests/test_timeout.py index b3d5d92..be55bf2 100644 --- a/tests/test_timeout.py +++ b/tests/test_timeout.py @@ -28,7 +28,8 @@ def on_start(self, ten_env: TenEnvTester) -> None: ten_env.on_start_done() property_json = {"num": 1, "str": "111"} - r = httpx.post("http://127.0.0.1:8888/cmd/abc", json=property_json, timeout=10) + r = httpx.post("http://127.0.0.1:8888/cmd/abc", + json=property_json, timeout=10) print(r) if r.status_code == httpx.codes.GATEWAY_TIMEOUT: ten_env.stop_test()