-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
use conftest.py in tests, eliminate star imports
- Loading branch information
Roy Wiggins
authored and
Roy Wiggins
committed
Dec 12, 2024
1 parent
6b2818c
commit 08a1ccb
Showing
19 changed files
with
236 additions
and
252 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
|
||
import os | ||
import socket | ||
import uuid | ||
from typing import Any, Callable, Dict | ||
|
||
import common # noqa: F401 | ||
import common.config as config | ||
import process # noqa: F401 | ||
import pytest | ||
import routing # noqa: F401 | ||
from bookkeeping import bookkeeper | ||
from common.types import Config | ||
|
||
|
||
def spy_on(mocker, obj) -> None: | ||
pieces = obj.split(".") | ||
module = ".".join(pieces[0:-1]) | ||
mocker.patch(obj, new=mocker.spy(eval(module), pieces[-1])) | ||
|
||
|
||
def spies(mocker, list_of_spies) -> None: | ||
for spy in list_of_spies: | ||
spy_on(mocker, spy) | ||
|
||
|
||
def attach_spies(mocker) -> None: | ||
spies( | ||
mocker, | ||
[ | ||
"routing.route_series.push_series_serieslevel", | ||
"routing.route_series.push_serieslevel_outgoing", | ||
"routing.route_studies.route_study", | ||
"routing.generate_taskfile.create_series_task", | ||
"routing.route_studies.move_study_folder", | ||
"routing.route_studies.push_studylevel_error", | ||
"routing.generate_taskfile.create_study_task", | ||
"routing.router.route_series", | ||
"routing.router.route_studies", | ||
"process.processor.process_series", | ||
# "process.process_series", | ||
"common.monitor.post", | ||
"common.monitor.send_event", | ||
"common.monitor.send_register_series", | ||
"common.monitor.send_register_task", | ||
"common.monitor.send_task_event", | ||
"common.monitor.async_send_task_event", | ||
"common.monitor.send_processor_output", | ||
"common.monitor.send_update_task", | ||
"common.notification.trigger_notification_for_rule", | ||
"common.notification.send_email", | ||
"uuid.uuid1" | ||
], | ||
) | ||
|
||
|
||
@pytest.fixture(scope="function") | ||
def mocked(mocker): | ||
mocker.resetall() | ||
attach_spies(mocker) | ||
return mocker | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def bookkeeper_port(): | ||
return random_port() | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def receiver_port(): | ||
return random_port() | ||
|
||
|
||
@pytest.fixture(scope="function", autouse=True) | ||
def mercure_config(fs, bookkeeper_port) -> Callable[[Dict], Config]: | ||
# TODO: config from previous calls seems to leak in here | ||
config_path = os.path.realpath(os.path.dirname(os.path.realpath(__file__)) + "/data/test_config.json") | ||
|
||
fs.add_real_file(config_path, target_path=config.configuration_filename, read_only=False) | ||
for k in ["incoming", "studies", "outgoing", "success", "error", "discard", "processing", "jobs"]: | ||
fs.create_dir(f"/var/{k}") | ||
|
||
def set_config(extra: Dict[Any, Any] = {}) -> Config: | ||
config.read_config() | ||
config.mercure = Config(**{**config.mercure.dict(), **extra}) # type: ignore | ||
print(config.mercure.targets) | ||
config.save_config() | ||
return config.mercure | ||
|
||
# set_config() | ||
# sqlite3 is not inside the fakefs so this is going to be a real file | ||
set_config({"bookkeeper": "sqlite:///tmp/mercure_bookkeeper_" + str(uuid.uuid4()) + ".db"}) | ||
|
||
bookkeeper_env = f"""PORT={bookkeeper_port} | ||
HOST=0.0.0.0 | ||
DATABASE_URL={config.mercure.bookkeeper}""" | ||
fs.create_file(bookkeeper.bk_config.config_filename, contents=bookkeeper_env) | ||
|
||
fs.add_real_directory(os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/../alembic')) | ||
fs.add_real_file(os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/../alembic.ini'), read_only=True) | ||
return set_config | ||
|
||
|
||
def random_port() -> int: | ||
""" | ||
Generate a free port number to use as an ephemeral endpoint. | ||
""" | ||
s = socket.socket() | ||
s.bind(('', 0)) # bind to any available port | ||
port = s.getsockname()[1] # get the port number | ||
s.close() | ||
return int(port) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import subprocess | ||
import tempfile | ||
from dataclasses import dataclass | ||
|
||
import pydicom | ||
import requests | ||
|
||
|
||
def send_dicom(ds, dest_host, dest_port) -> None: | ||
with tempfile.NamedTemporaryFile('w') as ds_temp: | ||
ds.save_as(ds_temp.name) | ||
subprocess.run(["dcmsend", dest_host, str(dest_port), ds_temp.name], check=True) | ||
|
||
|
||
@dataclass | ||
class MercureService: | ||
name: str | ||
command: str | ||
numprocs: int = 1 | ||
stopasgroup: bool = False | ||
startsecs: int = 0 | ||
|
||
|
||
def is_dicoms_received(mercure_base, dicoms) -> None: | ||
dicoms_recieved = set() | ||
for series_folder in (mercure_base / 'data' / 'incoming').glob('*/'): | ||
for dicom in series_folder.glob('*.dcm'): | ||
ds_ = pydicom.dcmread(dicom) | ||
assert ds_.SeriesInstanceUID == series_folder.name | ||
assert ds_.SOPInstanceUID not in dicoms_recieved | ||
dicoms_recieved.add(ds_.SOPInstanceUID) | ||
|
||
assert dicoms_recieved == set(ds.SOPInstanceUID for ds in dicoms) | ||
print(f"Received {len(dicoms)} dicoms as expected") | ||
|
||
|
||
def is_dicoms_in_folder(folder, dicoms) -> None: | ||
uids_found = set() | ||
print(f"Looking for dicoms in {folder}") | ||
dicoms_found = [] | ||
for f in folder.rglob('*'): | ||
if not f.is_file(): | ||
continue | ||
if f.suffix == '.dcm': | ||
dicoms_found.append(f) | ||
if f.suffix not in ('.error', '.tags'): | ||
dicoms_found.append(f) | ||
print("Dicoms", dicoms_found) | ||
for dicom in dicoms_found: | ||
|
||
try: | ||
uid = pydicom.dcmread(dicom).SOPInstanceUID | ||
uids_found.add(uid) | ||
except Exception: | ||
pass | ||
try: | ||
assert uids_found == set(ds.SOPInstanceUID for ds in dicoms), f"Dicoms missing from {folder}" | ||
except Exception: | ||
print("Expected dicoms not found") | ||
for dicom in folder.glob('**/*.dcm'): | ||
print(dicom) | ||
raise | ||
print(f"Found {len(dicoms)} dicoms in {folder.name} as expected") | ||
|
||
|
||
def is_series_registered(bookkeeper_port, dicoms) -> None: | ||
result = requests.get(f"http://localhost:{bookkeeper_port}/query/series", | ||
headers={"Authorization": "Token test"}) | ||
assert result.status_code == 200 | ||
result_json = result.json() | ||
assert set([r['series_uid'] for r in result_json]) == set([d.SeriesInstanceUID for d in dicoms]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.