tests.fixtures

Define pytest fixtures for use throughout the tests package and doctest tests.

 1"""Define `pytest` fixtures for use throughout the `tests` package and `doctest` tests."""
 2
 3from __future__ import annotations
 4
 5import socket
 6import subprocess
 7from typing import Iterator
 8
 9import pytest
10
11
12@pytest.fixture(scope='session')
13def dicom_storescp() -> str:
14    """Return the path to the `dicom-storescp` executable."""
15    import shutil
16
17    if (dicom_storescp := shutil.which('dicom-storescp')) is None:
18        pytest.skip('`dicom-storescp` not found. To install it, run `cargo install dicom-storescp`')
19
20    return dicom_storescp
21
22
23@pytest.fixture(scope='session')
24def localhost() -> Iterator[tuple[str, int]]:
25    """Query the OS for the first available port; return the hostname of the socket as well."""
26    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
27        sock.bind(('', 0))
28        host, port = sock.getsockname()
29        sock.close()
30        yield (host, port)
31
32
33@pytest.fixture(scope='session')
34def scpserver(dicom_storescp: str, localhost: tuple[str, int]) -> Iterator[str]:
35    """Start a DICOM SCP server for use with tests."""
36    host, port = localhost
37    with subprocess.Popen([dicom_storescp, '-p', str(port)], text=True) as sub_proc:
38        with pytest.raises(subprocess.TimeoutExpired):
39            sub_proc.wait(timeout=0.01)
40
41        assert None is sub_proc.returncode
42
43        try:
44            yield f'{host}:{port}'
45        finally:
46            sub_proc.terminate()
@pytest.fixture(scope='session')
def dicom_storescp() -> str:
13@pytest.fixture(scope='session')
14def dicom_storescp() -> str:
15    """Return the path to the `dicom-storescp` executable."""
16    import shutil
17
18    if (dicom_storescp := shutil.which('dicom-storescp')) is None:
19        pytest.skip('`dicom-storescp` not found. To install it, run `cargo install dicom-storescp`')
20
21    return dicom_storescp

Return the path to the dicom-storescp executable.

@pytest.fixture(scope='session')
def localhost() -> Iterator[tuple[str, int]]:
24@pytest.fixture(scope='session')
25def localhost() -> Iterator[tuple[str, int]]:
26    """Query the OS for the first available port; return the hostname of the socket as well."""
27    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
28        sock.bind(('', 0))
29        host, port = sock.getsockname()
30        sock.close()
31        yield (host, port)

Query the OS for the first available port; return the hostname of the socket as well.

@pytest.fixture(scope='session')
def scpserver(dicom_storescp: str, localhost: tuple[str, int]) -> Iterator[str]:
34@pytest.fixture(scope='session')
35def scpserver(dicom_storescp: str, localhost: tuple[str, int]) -> Iterator[str]:
36    """Start a DICOM SCP server for use with tests."""
37    host, port = localhost
38    with subprocess.Popen([dicom_storescp, '-p', str(port)], text=True) as sub_proc:
39        with pytest.raises(subprocess.TimeoutExpired):
40            sub_proc.wait(timeout=0.01)
41
42        assert None is sub_proc.returncode
43
44        try:
45            yield f'{host}:{port}'
46        finally:
47            sub_proc.terminate()

Start a DICOM SCP server for use with tests.