geotiff tests: gate GPU and HTTP tests on runtime availability#1873
Conversation
Two test infrastructure gaps caused noisy failures in restricted CI:
- test_cog.py::TestGPUCOGOverviews gated on import cupy alone, so a
sandbox with cupy installed but no working CUDA runtime ran the tests
instead of skipping. test_signature_annotations_1705.py had the same
shape using importlib.util.find_spec.
- HTTP tests stand up loopback servers with TCPServer(('127.0.0.1', 0)).
Sandboxes that deny loopback bind error out instead of skipping.
Add shared helpers in tests/conftest.py:
- gpu_available() probes cupy.cuda.is_available().
- loopback_available() probes a real socket bind once at collection.
- pytest_collection_modifyitems auto-skips any test module that imports
socketserver when loopback is unavailable; every HTTP test in this
directory does so to host its in-process server.
The two GPU files now route their skipif through gpu_available().
There was a problem hiding this comment.
Pull request overview
This PR makes GeoTIFF tests skip cleanly in restricted environments where CuPy is installed without usable CUDA, or loopback TCP binding is unavailable.
Changes:
- Adds shared GPU/CUDA and loopback availability checks in GeoTIFF test
conftest.py. - Adds a collection hook to skip socketserver-based tests when loopback bind is unavailable.
- Updates remaining GPU-gated tests to use runtime CUDA availability instead of CuPy import presence.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
xrspatial/geotiff/tests/conftest.py |
Adds shared availability helpers, skip markers, and loopback-based collection skipping. |
xrspatial/geotiff/tests/test_cog.py |
Switches GPU COG overview tests to skip unless CuPy + CUDA are available. |
xrspatial/geotiff/tests/test_signature_annotations_1705.py |
Switches GPU writer smoke test to skip unless CuPy + CUDA are available. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def pytest_collection_modifyitems(config, items): | ||
| """Auto-skip tests that stand up a loopback HTTP server when the | ||
| sandbox denies socket bind. A test opts in implicitly by importing | ||
| ``socketserver`` in its module; every HTTP test in this directory | ||
| does so to host a tiny in-process server. | ||
| """ | ||
| if _HAS_LOOPBACK: | ||
| return | ||
| skip_marker = pytest.mark.skip( | ||
| reason="loopback bind unavailable in this environment" | ||
| ) | ||
| for item in items: | ||
| module = getattr(item, 'module', None) | ||
| if module is None: | ||
| continue | ||
| if 'socketserver' in vars(module): | ||
| item.add_marker(skip_marker) | ||
|
|
||
|
|
…files The module-level check skipped every test in a file that imports socketserver. In files mixing HTTP and non-HTTP tests (test_miniswhite_backend_parity_1797.py, test_cog_http_concurrent.py, test_http_meta_buffer_1718.py) that suppressed coverage that does not need loopback at all -- a GPU smoke test, four direct read_ranges tests, and three in-memory metadata-buffer tests. Replace the module-level check with per-test source inspection: a test needs loopback iff its body or any fixture in its closure references ``socketserver.TCPServer(`` or ``_serve(``.
|
Addressed the per-test over-skip in Verified under simulated no-loopback (
Full geotiff suite under normal loopback: 2643 passed, 3 skipped, 11 pre-existing failures (same as before). |
Closes #1872.
Summary
GPU tests in
test_cog.py::TestGPUCOGOverviewsandtest_signature_annotations_1705.pygated onimport cupyalone. A sandbox withcupyinstalled but no working CUDA runtime ran those tests instead of skipping. The remaining GPU test files already use a_gpu_available()helper that checkscupy.cuda.is_available(). This PR routes the two stragglers through the same check.HTTP tests (
test_http_*.py,test_cog_http_*.py) stand up a loopback HTTP server withsocketserver.TCPServer(('127.0.0.1', 0), ...). Sandboxes that deny loopback bind error out instead of skipping. A collection hook intests/conftest.pynow probes loopback bind once and auto-skips any test module that importssocketserver, which covers every HTTP test in the directory without needing an explicit marker on each file.Test plan
test_http_range_validation_1735.pyskip cleanly when_HAS_LOOPBACK=Falseis patched.test_cog.py::TestGPUCOGOverviewsskip cleanly whengpu_available()is patched to return False.xrspatial/geotiff/tests/suite: 2635 passing, 7 skipped. The 8 remaining failures (test_predictor2_big_endian_gpu_1517.py,test_size_param_validation_gpu_vrt_1776.py::test_tile_size_positive_works,test_features.py::TestPalette) all reproduce onmainand are tracked separately.