From 67303920fe57355093042b85897cbf48857fb2df Mon Sep 17 00:00:00 2001 From: James Addison <55152140+jayaddison@users.noreply.github.com> Date: Fri, 12 Apr 2024 23:32:12 +0100 Subject: [PATCH] Make the test suite connectivity-agnostic (#12095) Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- sphinx/testing/fixtures.py | 48 +------------------- tests/roots/test-images/index.rst | 4 +- tests/roots/test-root/images.txt | 3 -- tests/test_builders/test_build_html_image.py | 8 ++-- tests/test_builders/test_build_latex.py | 40 +++++++++++++--- 5 files changed, 39 insertions(+), 64 deletions(-) diff --git a/sphinx/testing/fixtures.py b/sphinx/testing/fixtures.py index 95cf177c4af..6e1a1222a5f 100644 --- a/sphinx/testing/fixtures.py +++ b/sphinx/testing/fixtures.py @@ -7,7 +7,7 @@ import sys from collections import namedtuple from io import StringIO -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING import pytest @@ -236,52 +236,6 @@ def if_graphviz_found(app: SphinxTestApp) -> None: # NoQA: PT004 pytest.skip('graphviz "dot" is not available') -_HOST_ONLINE_ERROR = pytest.StashKey[Optional[str]]() - - -def _query(address: tuple[str, int]) -> str | None: - import socket - - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - try: - sock.settimeout(5) - sock.connect(address) - except OSError as exc: - # other type of errors are propagated - return str(exc) - return None - - -@pytest.fixture(scope='session') -def sphinx_remote_query_address() -> tuple[str, int]: - """Address to which a query is made to check that the host is online. - - By default, onlineness is tested by querying the DNS server ``1.1.1.1`` - but users concerned about privacy might change it in ``conftest.py``. - """ - return ('1.1.1.1', 80) - - -@pytest.fixture(scope='session') -def if_online( # NoQA: PT004 - request: pytest.FixtureRequest, - sphinx_remote_query_address: tuple[str, int], -) -> None: - """Skip the test if the host has no connection. - - Usage:: - - @pytest.mark.usefixtures('if_online') - def test_if_host_is_online(): ... - """ - if _HOST_ONLINE_ERROR not in request.session.stash: - # do not use setdefault() to avoid creating a socket connection - lookup_error = _query(sphinx_remote_query_address) - request.session.stash[_HOST_ONLINE_ERROR] = lookup_error - if (error := request.session.stash[_HOST_ONLINE_ERROR]) is not None: - pytest.skip('host appears to be offline (%s)' % error) - - @pytest.fixture(scope='session') def sphinx_test_tempdir(tmp_path_factory: Any) -> Path: """Temporary directory.""" diff --git a/tests/roots/test-images/index.rst b/tests/roots/test-images/index.rst index 14a2987a0dd..9b9aac1e595 100644 --- a/tests/roots/test-images/index.rst +++ b/tests/roots/test-images/index.rst @@ -23,7 +23,7 @@ test-image :target: https://www.python.org/ .. a remote image -.. image:: https://www.python.org/static/img/python-logo.png +.. image:: http://localhost:7777/sphinx.png .. non-exist remote image -.. image:: https://www.google.com/NOT_EXIST.PNG +.. image:: http://localhost:7777/NOT_EXIST.PNG diff --git a/tests/roots/test-root/images.txt b/tests/roots/test-root/images.txt index 1dc591a0262..5a096dc5b4d 100644 --- a/tests/roots/test-root/images.txt +++ b/tests/roots/test-root/images.txt @@ -12,9 +12,6 @@ Sphinx image handling .. an image with unspecified extension .. image:: img.* -.. a non-local image URI -.. image:: https://www.python.org/static/img/python-logo.png - .. an image with subdir and unspecified extension .. image:: subdir/simg.* diff --git a/tests/test_builders/test_build_html_image.py b/tests/test_builders/test_build_html_image.py index 66ba58df09c..08ed6187c81 100644 --- a/tests/test_builders/test_build_html_image.py +++ b/tests/test_builders/test_build_html_image.py @@ -5,15 +5,14 @@ import pytest -@pytest.mark.usefixtures('if_online') @pytest.mark.sphinx('html', testroot='images') def test_html_remote_images(app, status, warning): app.build(force_all=True) result = (app.outdir / 'index.html').read_text(encoding='utf8') - assert ('https://www.python.org/static/img/python-logo.png' in result) - assert not (app.outdir / 'python-logo.png').exists() + assert ('http://localhost:7777/sphinx.png' in result) + assert not (app.outdir / 'sphinx.png').exists() @pytest.mark.sphinx('html', testroot='image-escape') @@ -25,7 +24,6 @@ def test_html_encoded_image(app, status, warning): assert (app.outdir / '_images/img_#1.png').exists() -@pytest.mark.usefixtures('if_online') @pytest.mark.sphinx('html', testroot='remote-logo') def test_html_remote_logo(app, status, warning): app.build(force_all=True) diff --git a/tests/test_builders/test_build_latex.py b/tests/test_builders/test_build_latex.py index e9114b5c4de..0776c747a17 100644 --- a/tests/test_builders/test_build_latex.py +++ b/tests/test_builders/test_build_latex.py @@ -1,5 +1,6 @@ """Test the build process with LaTeX builder with the test root.""" +import http.server import os import re import subprocess @@ -17,6 +18,8 @@ from sphinx.util.osutil import ensuredir from sphinx.writers.latex import LaTeXTranslator +from tests.utils import http_server + try: from contextlib import chdir except ImportError: @@ -79,6 +82,28 @@ def skip_if_stylefiles_notfound(testfunc): return testfunc +class RemoteImageHandler(http.server.BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + + def do_GET(self): + content, content_type = None, None + if self.path == "/sphinx.png": + with open("tests/roots/test-local-logo/images/img.png", "rb") as f: + content = f.read() + content_type = "image/png" + + if content: + self.send_response(200, "OK") + self.send_header("Content-Length", str(len(content))) + self.send_header("Content-Type", content_type) + self.end_headers() + self.wfile.write(content) + else: + self.send_response(404, "Not Found") + self.send_header("Content-Length", "0") + self.end_headers() + + @skip_if_requested @skip_if_stylefiles_notfound @pytest.mark.parametrize( @@ -112,7 +137,8 @@ def test_build_latex_doc(app, engine, docclass, python_maximum_signature_line_le load_mappings(app) app.builder.init() LaTeXTranslator.ignore_missing_images = True - app.build(force_all=True) + with http_server(RemoteImageHandler): + app.build(force_all=True) # file from latex_additional_files assert (app.outdir / 'svgimg.svg').is_file() @@ -1398,21 +1424,21 @@ def test_latex_raw_directive(app, status, warning): assert 'LaTeX: abc def ghi' in result -@pytest.mark.usefixtures('if_online') @pytest.mark.sphinx('latex', testroot='images') def test_latex_images(app, status, warning): - app.build(force_all=True) + with http_server(RemoteImageHandler, port=7777): + app.build(force_all=True) result = (app.outdir / 'python.tex').read_text(encoding='utf8') # images are copied - assert '\\sphinxincludegraphics{{python-logo}.png}' in result - assert (app.outdir / 'python-logo.png').exists() + assert '\\sphinxincludegraphics{{sphinx}.png}' in result + assert (app.outdir / 'sphinx.png').exists() # not found images assert '\\sphinxincludegraphics{{NOT_EXIST}.PNG}' not in result assert ('WARNING: Could not fetch remote image: ' - 'https://www.google.com/NOT_EXIST.PNG [404]' in warning.getvalue()) + 'http://localhost:7777/NOT_EXIST.PNG [404]' in warning.getvalue()) # an image having target assert ('\\sphinxhref{https://www.sphinx-doc.org/}' @@ -1682,7 +1708,7 @@ def test_copy_images(app, status, warning): image.name for image in test_dir.rglob('*') if image.suffix in {'.gif', '.pdf', '.png', '.svg'} } - images.discard('python-logo.png') + images.discard('sphinx.png') assert images == { 'img.pdf', 'rimg.png',