diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 0bb570cedb..f968a437ef 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -7,13 +7,18 @@ on: pull_request: branches: ["master"] +defaults: + run: + shell: bash + jobs: tests: - name: "Python ${{ matrix.python-version }}" - runs-on: "ubuntu-latest" + name: "Python ${{ matrix.python-version }} (${{ matrix.os }})" + runs-on: "${{ matrix.os }}-latest" strategy: matrix: + os: ["ubuntu", "windows"] python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: @@ -32,3 +37,4 @@ jobs: run: "scripts/test" - name: "Enforce coverage" run: "scripts/coverage" + if: "matrix.os == 'ubuntu'" diff --git a/tests/client/test_async_client.py b/tests/client/test_async_client.py index 8d7eaa3c58..2e7025ebf3 100644 --- a/tests/client/test_async_client.py +++ b/tests/client/test_async_client.py @@ -18,7 +18,9 @@ async def test_get(server): assert response.http_version == "HTTP/1.1" assert response.headers assert repr(response) == "" - assert response.elapsed > timedelta(seconds=0) + # time related tests are flaky on windows + # Sanity test the property access and return type. + assert response.elapsed >= timedelta(seconds=0) @pytest.mark.parametrize( diff --git a/tests/test_multipart.py b/tests/test_multipart.py index 764f85a253..9e023cf2bc 100644 --- a/tests/test_multipart.py +++ b/tests/test_multipart.py @@ -3,6 +3,7 @@ import io import tempfile import typing +from pathlib import Path import pytest @@ -371,10 +372,15 @@ def test_multipart_encode_files_raises_exception_with_StringIO_content() -> None httpx.Request("POST", url, data={}, files=files) # type: ignore -def test_multipart_encode_files_raises_exception_with_text_mode_file() -> None: +def test_multipart_encode_files_raises_exception_with_text_mode_file( + tmp_path: Path, +) -> None: url = "https://www.example.com" - with tempfile.TemporaryFile(mode="w") as upload: - files = {"file": ("test.txt", upload, "text/plain")} + # TemporaryFiles are always binary mode on windows. + # For this test case where we need a text-mode file. + tmp_path.joinpath("test.txt").write_text("content") + with tmp_path.joinpath("test.txt").open() as temp: + files = {"file": ("test.txt", temp, "text/plain")} with pytest.raises(TypeError): httpx.Request("POST", url, data={}, files=files) # type: ignore diff --git a/tests/test_timeouts.py b/tests/test_timeouts.py index 666cc8e376..9cd472edc8 100644 --- a/tests/test_timeouts.py +++ b/tests/test_timeouts.py @@ -1,3 +1,5 @@ +import sys + import pytest import httpx @@ -12,6 +14,9 @@ async def test_read_timeout(server): await client.get(server.url.copy_with(path="/slow_response")) +@pytest.mark.skipif( + sys.platform == "win32", reason="time related tests are flaky on win32" +) @pytest.mark.anyio async def test_write_timeout(server): timeout = httpx.Timeout(None, write=1e-6) diff --git a/tests/test_utils.py b/tests/test_utils.py index f98a18f2cd..a334161897 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,6 +2,7 @@ import logging import os import random +import sys import certifi import pytest @@ -122,6 +123,7 @@ def test_logging_redirect_chain(server, caplog): ] +@pytest.mark.skipif(sys.platform == "win32", reason="os path sep escaped on windows") def test_logging_ssl(caplog): caplog.set_level(logging.DEBUG) with httpx.Client(): @@ -155,7 +157,9 @@ def test_get_ssl_cert_file(): os.environ["SSL_CERT_FILE"] = str(TESTS_DIR / "test_utils.py") # SSL_CERT_FILE is correctly set, SSL_CERT_DIR is not set. ca_bundle = get_ca_bundle_from_env() - assert ca_bundle is not None and ca_bundle.endswith("tests/test_utils.py") + assert ca_bundle is not None and ca_bundle.endswith( + os.path.join("tests", "test_utils.py") + ) os.environ["SSL_CERT_FILE"] = "wrongfile" # SSL_CERT_FILE is set with wrong file, SSL_CERT_DIR is not set. @@ -170,7 +174,9 @@ def test_get_ssl_cert_file(): os.environ["SSL_CERT_FILE"] = str(TESTS_DIR / "test_utils.py") # Two environments is correctly set. ca_bundle = get_ca_bundle_from_env() - assert ca_bundle is not None and ca_bundle.endswith("tests/test_utils.py") + assert ca_bundle is not None and ca_bundle.endswith( + os.path.join("tests", "test_utils.py") + ) os.environ["SSL_CERT_FILE"] = "wrongfile" # Two environments is set but SSL_CERT_FILE is not a file.