diff --git a/pyproject.toml b/pyproject.toml index a91273b..e4f1440 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,7 @@ dev-dependencies = [ "pytest>=7.4.0", "pytest-asyncio>=0.21.1", "pytest-cov>=4.1.0", + "pytest-env>=1.1.5", "pytest-mock>=3.11.1", "ruff>=0.0.278", "types-protobuf>=4.24.0.20240311", diff --git a/tests/conftest.py b/tests/conftest.py index e429135..16ee827 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,4 @@ -import asyncio -import logging -from typing import Any, AsyncGenerator, Literal, Mapping +from typing import Any, Mapping import nanoid import pytest @@ -8,21 +6,15 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter -from websockets.server import serve -from replit_river.client import Client -from replit_river.client_transport import UriAndMetadata from replit_river.error_schema import RiverError from replit_river.rpc import ( GenericRpcHandler, TransportMessage, ) -from replit_river.server import Server -from replit_river.transport_options import TransportOptions -from tests.river_fixtures.logging import NoErrors # Modular fixtures -pytest_plugins = ["tests.river_fixtures.logging"] +pytest_plugins = ["tests.river_fixtures.logging", "tests.river_fixtures.clientserver"] HandlerMapping = Mapping[tuple[str, str], tuple[str, GenericRpcHandler]] @@ -68,58 +60,6 @@ def deserialize_error(response: dict) -> RiverError: return RiverError.model_validate(response) -@pytest.fixture -def transport_options() -> TransportOptions: - return TransportOptions() - - -@pytest.fixture -def server_handlers(handlers: HandlerMapping) -> HandlerMapping: - return handlers - - -@pytest.fixture -def server( - transport_options: TransportOptions, server_handlers: HandlerMapping -) -> Server: - server = Server(server_id="test_server", transport_options=transport_options) - server.add_rpc_handlers(server_handlers) - return server - - -@pytest.fixture -async def client( - server: Server, - transport_options: TransportOptions, - no_logging_error: NoErrors, -) -> AsyncGenerator[Client, None]: - async def websocket_uri_factory() -> UriAndMetadata[None]: - return { - "uri": "ws://localhost:8765", - "metadata": None, - } - - try: - async with serve(server.serve, "localhost", 8765): - client: Client[Literal[None]] = Client[None]( - uri_and_metadata_factory=websocket_uri_factory, - client_id="test_client", - server_id="test_server", - transport_options=transport_options, - ) - try: - yield client - finally: - logging.debug("Start closing test client : %s", "test_client") - await client.close() - finally: - await asyncio.sleep(1) - logging.debug("Start closing test server") - await server.close() - # Server should close normally - no_logging_error() - - @pytest.fixture(scope="session") def span_exporter() -> InMemorySpanExporter: exporter = InMemorySpanExporter() diff --git a/tests/river_fixtures/clientserver.py b/tests/river_fixtures/clientserver.py new file mode 100644 index 0000000..b54489b --- /dev/null +++ b/tests/river_fixtures/clientserver.py @@ -0,0 +1,65 @@ +import asyncio +import logging +from typing import AsyncGenerator, Literal + +import pytest +from websockets.server import serve + +from replit_river.client import Client +from replit_river.client_transport import UriAndMetadata +from replit_river.server import Server +from replit_river.transport_options import TransportOptions +from tests.conftest import HandlerMapping +from tests.river_fixtures.logging import NoErrors # noqa: E402 + + +@pytest.fixture +def transport_options() -> TransportOptions: + return TransportOptions() + + +@pytest.fixture +def server_handlers(handlers: HandlerMapping) -> HandlerMapping: + return handlers + + +@pytest.fixture +def server( + transport_options: TransportOptions, server_handlers: HandlerMapping +) -> Server: + server = Server(server_id="test_server", transport_options=transport_options) + server.add_rpc_handlers(server_handlers) + return server + + +@pytest.fixture +async def client( + server: Server, + transport_options: TransportOptions, + no_logging_error: NoErrors, +) -> AsyncGenerator[Client, None]: + async def websocket_uri_factory() -> UriAndMetadata[None]: + return { + "uri": "ws://localhost:8765", + "metadata": None, + } + + try: + async with serve(server.serve, "localhost", 8765): + client: Client[Literal[None]] = Client[None]( + uri_and_metadata_factory=websocket_uri_factory, + client_id="test_client", + server_id="test_server", + transport_options=transport_options, + ) + try: + yield client + finally: + logging.debug("Start closing test client : %s", "test_client") + await client.close() + finally: + await asyncio.sleep(1) + logging.debug("Start closing test server") + await server.close() + # Server should close normally + no_logging_error() diff --git a/uv.lock b/uv.lock index 04c46d8..82de526 100644 --- a/uv.lock +++ b/uv.lock @@ -555,6 +555,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, ] +[[package]] +name = "pytest-env" +version = "1.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/31/27f28431a16b83cab7a636dce59cf397517807d247caa38ee67d65e71ef8/pytest_env-1.1.5.tar.gz", hash = "sha256:91209840aa0e43385073ac464a554ad2947cc2fd663a9debf88d03b01e0cc1cf", size = 8911 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/b8/87cfb16045c9d4092cfcf526135d73b88101aac83bc1adcf82dfb5fd3833/pytest_env-1.1.5-py3-none-any.whl", hash = "sha256:ce90cf8772878515c24b31cd97c7fa1f4481cd68d588419fd45f10ecaee6bc30", size = 6141 }, +] + [[package]] name = "pytest-mock" version = "3.14.0" @@ -595,6 +607,7 @@ dev = [ { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, + { name = "pytest-env" }, { name = "pytest-mock" }, { name = "ruff" }, { name = "types-nanoid" }, @@ -626,6 +639,7 @@ dev = [ { name = "pytest", specifier = ">=7.4.0" }, { name = "pytest-asyncio", specifier = ">=0.21.1" }, { name = "pytest-cov", specifier = ">=4.1.0" }, + { name = "pytest-env", specifier = ">=1.1.5" }, { name = "pytest-mock", specifier = ">=3.11.1" }, { name = "ruff", specifier = ">=0.0.278" }, { name = "types-nanoid", specifier = ">=2.0.0.20240601" },