From d9c8789beff0175ca79d76783649b068b878697a Mon Sep 17 00:00:00 2001 From: Joshua Watt Date: Fri, 2 Aug 2024 10:17:10 -0600 Subject: [PATCH] Remove pytest-server-fixtures The upstream for this module appears dead, and it is broken with the latest version of python due to [1], so remove it and implement the functionality locally [1]: https://github.com/man-group/pytest-plugins/issues/224 --- pyproject.toml | 1 - tests/__init__.py | 0 tests/conftest.py | 9 +++-- tests/http.py | 74 ++++++++++++++++++++++++++++++++++++++ tests/test_model_source.py | 9 ++--- 5 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/http.py diff --git a/pyproject.toml b/pyproject.toml index d1c45a4..45c4512 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,6 @@ dev = [ "pyshacl >= 0.25.0", "pytest >= 7.4", "pytest-cov >= 4.1", - "pytest-server-fixtures >= 1.7", ] [project.urls] diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py index b76561e..5af0785 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,8 +9,8 @@ import shutil import subprocess import time +from .http import HTTPTestServer -from pytest_server_fixtures.http import SimpleHTTPTestServer from pathlib import Path THIS_FILE = Path(__file__) @@ -21,19 +21,18 @@ @pytest.fixture def http_server(): - with SimpleHTTPTestServer() as s: + with HTTPTestServer() as s: s.start() yield s @pytest.fixture(scope="session") def model_server(): - with SimpleHTTPTestServer() as s: - root = Path(s.document_root) + with HTTPTestServer() as s: for p in MODEL_DIR.iterdir(): if not p.is_file(): continue - shutil.copyfile(p, root / p.name) + shutil.copyfile(p, s.document_root / p.name) s.start() yield s.uri diff --git a/tests/http.py b/tests/http.py new file mode 100644 index 0000000..82d90cc --- /dev/null +++ b/tests/http.py @@ -0,0 +1,74 @@ +# +# Copyright (c) 2024 Joshua Watt +# +# SPDX-License-Identifier: MIT + +import socket +import subprocess +import sys +import tempfile +import time + +from pathlib import Path +from contextlib import closing + + +def get_ephemeral_port(host): + with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind((host, 0)) + return s.getsockname()[1] + + +class HTTPTestServer(object): + def __init__(self): + self.p = None + self.temp_dir = None + + def start(self): + assert self.p is None, "Server already started" + + self.host = "localhost" + self.port = get_ephemeral_port(self.host) + self.p = subprocess.Popen( + [sys.executable, "-m", "http.server", "--bind", self.host, str(self.port)], + cwd=self.document_root, + ) + self.uri = f"http://{self.host}:{self.port}" + + # Wait for server to start + start_time = time.monotonic() + while time.monotonic() < start_time + 30: + assert self.p.poll() is None + with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: + try: + s.connect((self.host, self.port)) + return + + except ConnectionRefusedError: + continue + + # Timeout + self.p.terminate() + self.p.wait() + assert False, "Timeout waiting for server to be ready" + + def stop(self): + if self.p is None: + return + + self.p.terminate() + self.p.wait() + + def __enter__(self): + self.temp_dir = tempfile.TemporaryDirectory() + return self + + def __exit__(self, typ, value, tb): + self.stop() + self.temp_dir.cleanup() + self.temp_dir = None + + @property + def document_root(self): + return Path(self.temp_dir.name) diff --git a/tests/test_model_source.py b/tests/test_model_source.py index 661f942..379c606 100644 --- a/tests/test_model_source.py +++ b/tests/test_model_source.py @@ -3,7 +3,6 @@ # # SPDX-License-Identifier: MIT -import os import shutil import subprocess import pytest @@ -289,12 +288,8 @@ def test_context_url(model_server): def test_context_args(http_server): - shutil.copyfile( - TEST_CONTEXT, os.path.join(http_server.document_root, "context.json") - ) - shutil.copyfile( - TEST_CONTEXT, os.path.join(http_server.document_root, "context2.json") - ) + shutil.copyfile(TEST_CONTEXT, http_server.document_root / "context.json") + shutil.copyfile(TEST_CONTEXT, http_server.document_root / "context2.json") def do_test(*, contexts=[], url_contexts=[]): cmd = [