diff --git a/pytest_httpserver/__init__.py b/pytest_httpserver/__init__.py index e81e58a..00d5cf1 100644 --- a/pytest_httpserver/__init__.py +++ b/pytest_httpserver/__init__.py @@ -17,6 +17,7 @@ "RequestHandler", "RequestMatcher", "RequestMatcherKwargs", + "ServerOptions", "URIPattern", "WaitingSettings", ] @@ -34,5 +35,6 @@ from .httpserver import RequestHandler from .httpserver import RequestMatcher from .httpserver import RequestMatcherKwargs +from .httpserver import ServerOptions from .httpserver import URIPattern from .httpserver import WaitingSettings diff --git a/pytest_httpserver/httpserver.py b/pytest_httpserver/httpserver.py index 110c428..275ec69 100644 --- a/pytest_httpserver/httpserver.py +++ b/pytest_httpserver/httpserver.py @@ -18,6 +18,7 @@ from contextlib import contextmanager from contextlib import suppress from copy import copy +from dataclasses import dataclass from enum import Enum from http import HTTPStatus from re import Pattern @@ -947,6 +948,13 @@ def format_host(host: str) -> str: return host +@dataclass +class ServerOptions: + default_waiting_settings: WaitingSettings | None = None + threaded: bool = False + startup_timeout: float | None = None + + class HTTPServer(HTTPServerBase): # pylint: disable=too-many-instance-attributes """ Server instance which manages handlers to serve pre-defined requests. @@ -1001,6 +1009,17 @@ def __init__( self.startup_timeout = startup_timeout self._readiness_check_pending = False + @classmethod + def with_options(cls, host: str, port: int, ssl_context: SSLContext | None, options: ServerOptions) -> Self: + return cls( + host, + port, + ssl_context, + default_waiting_settings=options.default_waiting_settings, + threaded=options.threaded, + startup_timeout=options.startup_timeout, + ) + def start(self) -> None: super().start() self._readiness_check_pending = self.startup_timeout is not None diff --git a/pytest_httpserver/pytest_plugin.py b/pytest_httpserver/pytest_plugin.py index f19ec58..0db4cda 100644 --- a/pytest_httpserver/pytest_plugin.py +++ b/pytest_httpserver/pytest_plugin.py @@ -6,6 +6,7 @@ import pytest from .httpserver import HTTPServer +from .httpserver import ServerOptions if TYPE_CHECKING: from collections.abc import Generator @@ -44,10 +45,16 @@ def httpserver_ssl_context() -> None: return None +@pytest.fixture(scope="session") +def httpserver_options() -> ServerOptions: + return ServerOptions() + + @pytest.fixture(scope="session") def make_httpserver( httpserver_listen_address: tuple[str | None, int | None], httpserver_ssl_context: SSLContext | None, + httpserver_options: ServerOptions, ) -> Generator[HTTPServer, None, None]: host, port = httpserver_listen_address if not host: @@ -55,7 +62,12 @@ def make_httpserver( if not port: port = HTTPServer.DEFAULT_LISTEN_PORT - server = HTTPServer(host=host, port=port, ssl_context=httpserver_ssl_context) + server = HTTPServer.with_options( + host=host, + port=port, + ssl_context=httpserver_ssl_context, + options=httpserver_options, + ) server.start() yield server server.clear() @@ -80,8 +92,14 @@ def httpserver(make_httpserver: HTTPServer) -> HTTPServer: @pytest.fixture(scope="session") def make_httpserver_ipv4( httpserver_ssl_context: SSLContext | None, + httpserver_options: ServerOptions, ) -> Generator[HTTPServer, None, None]: - server = HTTPServer(host="127.0.0.1", port=0, ssl_context=httpserver_ssl_context) + server = HTTPServer.with_options( + host="127.0.0.1", + port=0, + ssl_context=httpserver_ssl_context, + options=httpserver_options, + ) server.start() yield server server.clear() @@ -99,8 +117,14 @@ def httpserver_ipv4(make_httpserver_ipv4: HTTPServer) -> HTTPServer: @pytest.fixture(scope="session") def make_httpserver_ipv6( httpserver_ssl_context: SSLContext | None, + httpserver_options: ServerOptions, ) -> Generator[HTTPServer, None, None]: - server = HTTPServer(host="::1", port=0, ssl_context=httpserver_ssl_context) + server = HTTPServer.with_options( + host="::1", + port=0, + ssl_context=httpserver_ssl_context, + options=httpserver_options, + ) server.start() yield server server.clear() diff --git a/tests/test_options.py b/tests/test_options.py new file mode 100644 index 0000000..2b6d9e8 --- /dev/null +++ b/tests/test_options.py @@ -0,0 +1,41 @@ +from inspect import signature + +from pytest_httpserver import HTTPServer +from pytest_httpserver import ServerOptions +from pytest_httpserver import WaitingSettings + + +def test_httpserver_options() -> None: + options = ServerOptions( + startup_timeout=60, + threaded=True, + default_waiting_settings=WaitingSettings(timeout=5), + ) + + server = HTTPServer.with_options( + host="localhost", + port=0, + ssl_context=None, + options=options, + ) + + assert server.startup_timeout == 60 + assert server.threaded is True + assert server.default_waiting_settings.timeout == 5 + + +def test_constructor_signature_matches_with_server_options() -> None: + # compares that ServerOptions default values matches with HTTPServer + # constructor defaults + + httpserver_sig = signature(HTTPServer.__init__) + options_sig = signature(ServerOptions.__init__) + for param_name, options_param in options_sig.parameters.items(): + if param_name == "self": + continue + httpserver_param = httpserver_sig.parameters.get(param_name) + assert httpserver_param is not None, f"Parameter {param_name} missing in HTTPServer" + assert httpserver_param.default == options_param.default, ( + f"Default value for parameter {param_name} does not match: " + f"{httpserver_param.default} != {options_param.default}" + ) diff --git a/tests/test_release.py b/tests/test_release.py index 8643d11..2203aab 100644 --- a/tests/test_release.py +++ b/tests/test_release.py @@ -219,6 +219,7 @@ def test_sdist_contents(build: Build, version: str): "examples", "test_bake.py", "test_blocking_httpserver.py", + "test_options.py", "test_handler_errors.py", "test_headers.py", "test_hooks.py",