diff --git a/.gitignore b/.gitignore index 2b86234..847f968 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .ten __pycache__ .pytest_cache +.coverage \ No newline at end of file diff --git a/http_server_extension.py b/http_server_extension.py index 7959f21..0156037 100644 --- a/http_server_extension.py +++ b/http_server_extension.py @@ -6,6 +6,7 @@ AsyncExtension, AsyncTenEnv, Cmd, + Data, StatusCode, CmdResult, ) @@ -54,6 +55,32 @@ async def handle_post_cmd(self, request): "failed to handle request with unknown exception, err {}".format(e)) return web.Response(status=500) + # POST /data/{data_name} + async def handle_post_data(self, request): + ten_env = self.ten_env + + try: + data_name = request.match_info.get('data_name') + + req_json = await request.json() + input = json.dumps(req_json, ensure_ascii=False) + + ten_env.log_debug( + f"process incoming request {request.method} {request.path} {input}") + + data = Data.create(data_name) + data.set_property_from_json("", input) + await ten_env.send_data(data) + + # return response + return web.Response(status=200) + except json.JSONDecodeError: + return web.Response(status=400) + except Exception as e: + ten_env.log_warn( + "failed to handle request with unknown exception, err {}".format(e)) + return web.Response(status=500) + async def on_start(self, ten_env: AsyncTenEnv): if await ten_env.is_property_exist("listen_addr"): self.listen_addr = await ten_env.get_property_string("listen_addr") @@ -65,6 +92,7 @@ async def on_start(self, ten_env: AsyncTenEnv): f"http server listening on {self.listen_addr}:{self.listen_port}") self.app.router.add_post("/cmd/{cmd_name}", self.handle_post_cmd) + self.app.router.add_post("/data/{data_name}", self.handle_post_data) self.runner = web.AppRunner(self.app) await self.runner.setup() site = web.TCPSite(self.runner, self.listen_addr, self.listen_port) diff --git a/tests/test_4xx.py b/tests/test_4xx.py index 2ed9aeb..785fa3c 100644 --- a/tests/test_4xx.py +++ b/tests/test_4xx.py @@ -18,7 +18,7 @@ def on_start(self, ten_env: TenEnvTester) -> None: property_json = {"num": 1, "str": "111"} r = httpx.post("http://127.0.0.1:8888/cmd", json=property_json) - print(r) + ten_env.log_debug(f"{r}") if r.status_code == httpx.codes.NOT_FOUND: ten_env.stop_test() @@ -29,21 +29,30 @@ def on_start(self, ten_env: TenEnvTester) -> None: property_json = {"num": 1, "str": "111"} r = httpx.post("http://127.0.0.1:8888/cmd/aaa/123", json=property_json) - print(r) + ten_env.log_debug(f"{r}") if r.status_code == httpx.codes.NOT_FOUND: ten_env.stop_test() -class ExtensionTester400BadRequest(ExtensionTester): +class ExtensionTesterCmd400BadRequest(ExtensionTester): def on_start(self, ten_env: TenEnvTester) -> None: ten_env.on_start_done() property_str = '{num": 1, "str": "111"}' # not a valid json r = httpx.post("http://127.0.0.1:8888/cmd/aaa", content=property_str) - print(r) + ten_env.log_debug(f"{r}") if r.status_code == httpx.codes.BAD_REQUEST: ten_env.stop_test() +class ExtensionTesterData400BadRequest(ExtensionTester): + def on_start(self, ten_env: TenEnvTester) -> None: + ten_env.on_start_done() + + property_str = '{num": 1, "str": "111"}' # not a valid json + r = httpx.post("http://127.0.0.1:8888/data/aaa", content=property_str) + ten_env.log_debug(f"{r}") + if r.status_code == httpx.codes.BAD_REQUEST: + ten_env.stop_test() def test_4xx(): tester_404_1 = ExtensionTester404NotFound1() @@ -54,6 +63,10 @@ def test_4xx(): tester_404_2.set_test_mode_single("http_server_python") tester_404_2.run() - tester_400 = ExtensionTester400BadRequest() - tester_400.set_test_mode_single("http_server_python") - tester_400.run() + tester_cmd_400 = ExtensionTesterCmd400BadRequest() + tester_cmd_400.set_test_mode_single("http_server_python") + tester_cmd_400.run() + + tester_data_400 = ExtensionTesterData400BadRequest() + tester_data_400.set_test_mode_single("http_server_python") + tester_data_400.run() diff --git a/tests/test_5xx.py b/tests/test_5xx.py index 32b5309..609fb4b 100644 --- a/tests/test_5xx.py +++ b/tests/test_5xx.py @@ -24,7 +24,7 @@ def __init__(self): self.thread = None def on_cmd(self, ten_env: TenEnvTester, cmd: Cmd) -> None: - print(f"on_cmd name {cmd.get_name()}") + ten_env.log_debug(f"on_cmd name {cmd.get_name()}") ten_env.return_result(CmdResult.create(StatusCode.ERROR), cmd) def on_start(self, ten_env: TenEnvTester) -> None: @@ -38,7 +38,7 @@ def _async_test(self, ten_env: TenEnvTester) -> 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) + ten_env.log_debug(f"{r}") if r.status_code >= 500: ten_env.stop_test() diff --git a/tests/test_basic.py b/tests/test_cmd.py similarity index 89% rename from tests/test_basic.py rename to tests/test_cmd.py index b483ea5..6b99806 100644 --- a/tests/test_basic.py +++ b/tests/test_cmd.py @@ -17,13 +17,13 @@ import math -class ExtensionTesterBasic(ExtensionTester): +class ExtensionTesterCmd(ExtensionTester): def __init__(self): super().__init__() self.thread = None def on_cmd(self, ten_env: TenEnvTester, cmd: Cmd) -> None: - print(f"on_cmd name {cmd.get_name()}") + ten_env.log_debug(f"on_cmd name {cmd.get_name()}") num_val = cmd.get_property_int('num') assert num_val == 1 @@ -50,17 +50,17 @@ def _async_test(self, ten_env: TenEnvTester) -> None: r = httpx.post("http://127.0.0.1:8888/cmd/abc", json=property_json, timeout=5) - print(r) + ten_env.log_debug(f"{r}") if r.status_code == httpx.codes.OK: ten_env.stop_test() -def test_basic(): - tester = ExtensionTesterBasic() +def test_cmd(): + tester = ExtensionTesterCmd() tester.set_test_mode_single("http_server_python") tester.run() if __name__ == "__main__": - test_basic() + test_cmd() diff --git a/tests/test_data.py b/tests/test_data.py new file mode 100644 index 0000000..56ba505 --- /dev/null +++ b/tests/test_data.py @@ -0,0 +1,66 @@ +# +# 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, + Data, + CmdResult, + StatusCode, +) +import httpx +import threading +import math + + +class ExtensionTesterData(ExtensionTester): + def __init__(self): + super().__init__() + self.thread = None + + def on_data(self, ten_env: TenEnvTester, data: Data) -> None: + ten_env.log_debug(f"on_data name {data.get_name()}") + + num_val = data.get_property_int('num') + assert num_val == 1 + str_val = data.get_property_string('str') + assert str_val == '111' + unicode_str_val = data.get_property_string('unicode_str') + assert unicode_str_val == '你好!' + num_float_val = data.get_property_float('num_float') + assert math.isclose(num_float_val, -1.5) + + + def on_start(self, ten_env: TenEnvTester) -> None: + + self.thread = threading.Thread( + target=self._async_test, args=[ten_env]) + self.thread.start() + + ten_env.on_start_done() + + def _async_test(self, ten_env: TenEnvTester) -> None: + property_json = {"num": 1, "num_float": - + 1.5, "str": "111", "unicode_str": "你好!"} + + r = httpx.post("http://127.0.0.1:8888/data/abc", + json=property_json, timeout=5) + ten_env.log_debug(f"{r}") + + if r.status_code == httpx.codes.OK: + ten_env.stop_test() + + +def test_data(): + tester = ExtensionTesterData() + tester.set_test_mode_single("http_server_python") + tester.run() + + +if __name__ == "__main__": + test_data() diff --git a/tests/test_set_property.py b/tests/test_set_property.py index d56abe9..b5e27f9 100644 --- a/tests/test_set_property.py +++ b/tests/test_set_property.py @@ -22,7 +22,7 @@ def __init__(self): self.thread = None def on_cmd(self, ten_env: TenEnvTester, cmd: Cmd) -> None: - print(f"on_cmd name {cmd.get_name()}") + ten_env.log_debug(f"on_cmd name {cmd.get_name()}") ten_env.return_result(CmdResult.create(StatusCode.OK), cmd) def on_start(self, ten_env: TenEnvTester) -> None: @@ -37,7 +37,7 @@ def _async_test(self, ten_env: TenEnvTester) -> 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) + ten_env.log_debug(f"{r}") if r.status_code == httpx.codes.OK: ten_env.stop_test() diff --git a/tests/test_timeout.py b/tests/test_timeout.py index 0e84f3d..4229bf5 100644 --- a/tests/test_timeout.py +++ b/tests/test_timeout.py @@ -19,7 +19,7 @@ class ExtensionTesterTimeout(ExtensionTester): def on_cmd(self, ten_env: TenEnvTester, cmd: Cmd) -> None: - print(f"on_cmd name {cmd.get_name()}") + ten_env.log_debug(f"on_cmd name {cmd.get_name()}") # NOTE: DON'T return result so that timeout will occur # ten_env.return_result(CmdResult.create(StatusCode.OK), cmd) pass @@ -30,7 +30,7 @@ def on_start(self, ten_env: TenEnvTester) -> None: property_json = {"num": 1, "str": "111"} r = httpx.post("http://127.0.0.1:8888/cmd/abc", json=property_json, timeout=10) - print(r) + ten_env.log_debug(f"{r}") if r.status_code == httpx.codes.GATEWAY_TIMEOUT: ten_env.stop_test()