Mercurial > hg > orthanc-tests
changeset 776:932d09c3be0a
merge
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 21 Jan 2025 18:50:03 +0100 (4 months ago) |
parents | be7312788221 (current diff) 82c61e3f7737 (diff) |
children | 287aae544b31 |
files | |
diffstat | 6 files changed, 254 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NewTests/CGet/docker-compose-c-get.yml Tue Jan 21 18:50:03 2025 +0100 @@ -0,0 +1,69 @@ +services: + + orthanc-a: + image: ${ORTHANC_IMAGE_UNDER_TESTS:-orthancteam/orthanc:latest} + container_name: orthanc-a + restart: unless-stopped + ports: ["8072:8042"] + volumes: ["storage-orthanc-a:/var/lib/orthanc/db"] + environment: + VERBOSE_STARTUP: "true" + VERBOSE_ENABLED: "true" + ORTHANC_JSON: | + { + "AuthenticationEnabled": false, + "DicomAet": "ORTHANCA", + "Name": "Orthanc A", + "OverwriteInstances": true, + + "DicomModalities": { + "b": { + "AET": "ORTHANCB", + "Port": 4242, + "Host": "orthanc-b" + }, + "b-move": { + "AET": "ORTHANCB", + "Port": 4242, + "Host": "orthanc-b", + "RetrieveMethod": "C-MOVE" + }, + "b-get": { + "AET": "ORTHANCB", + "Port": 4242, + "Host": "orthanc-b", + "RetrieveMethod": "C-GET" + } + } + } + + + orthanc-b: + # last version before C-GET SCU + image: orthancteam/orthanc:24.12.0 + container_name: orthanc-b + restart: unless-stopped + ports: ["8073:8042"] + volumes: ["storage-orthanc-b:/var/lib/orthanc/db"] + environment: + VERBOSE_STARTUP: "true" + VERBOSE_ENABLED: "true" + ORTHANC_JSON: | + { + "AuthenticationEnabled": false, + "DicomAet": "ORTHANCB", + "Name": "Orthanc B", + "OverwriteInstances": true, + + "DicomModalities": { + "a": { + "AET": "ORTHANCA", + "Port": 4242, + "Host": "orthanc-a" + } + } + } + +volumes: + storage-orthanc-a: + storage-orthanc-b:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NewTests/CGet/get-scp.py Tue Jan 21 18:50:03 2025 +0100 @@ -0,0 +1,104 @@ +import os + +from pydicom import dcmread +from pydicom.dataset import Dataset + +from pydicom.uid import ImplicitVRLittleEndian, ExplicitVRLittleEndian +from pynetdicom import AE, StoragePresentationContexts, evt, AllStoragePresentationContexts +from pynetdicom.sop_class import PatientRootQueryRetrieveInformationModelGet, StudyRootQueryRetrieveInformationModelGet, MRImageStorage, CTImageStorage + +import logging + +# Configure logging +logging.basicConfig(level=logging.DEBUG) + +def transform_to_transfer_syntax(dataset, target_transfer_syntax): + # Create a new dataset with the new transfer syntax + new_dataset = Dataset() + new_dataset.file_meta = Dataset() + new_dataset.file_meta.TransferSyntaxUID = target_transfer_syntax + new_dataset.update(dataset) + return new_dataset + +# Implement the handler for evt.EVT_C_GET +def handle_get(event): + """Handle a C-GET request event.""" + ds = event.identifier + if 'QueryRetrieveLevel' not in ds: + # Failure + yield 0xC000, None + return + + # Import stored SOP Instances + instances = [] + matching = [] + fdir = '/home/alain/o/orthanc-tests/Database/Brainix/Epi' + for fpath in os.listdir(fdir): + instances.append(dcmread(os.path.join(fdir, fpath))) + + if ds.QueryRetrieveLevel == 'PATIENT': + if 'PatientID' in ds: + matching = [ + inst for inst in instances if inst.PatientID == ds.PatientID + ] + elif ds.QueryRetrieveLevel == 'STUDY': + if 'StudyInstanceUID' in ds: + matching = [ + inst for inst in instances if inst.StudyInstanceUID == ds.StudyInstanceUID + ] + + print(f"GET-SCP: instances to send: {len(instances)}") + # Yield the total number of C-STORE sub-operations required + yield len(instances) + + # Yield the matching instances + for instance in matching: + # Check if C-CANCEL has been received + if event.is_cancelled: + yield (0xFE00, None) + return + + # Pending + accepted_transfer_syntax = event.assoc.accepted_contexts[0].transfer_syntax + + if accepted_transfer_syntax != instance.file_meta.TransferSyntaxUID: + transformed_instance = transform_to_transfer_syntax(instance, accepted_transfer_syntax) + yield (0xFF00, transformed_instance) + else: + yield (0xFF00, instance) + + +handlers = [(evt.EVT_C_GET, handle_get)] + +# Create application entity +ae = AE("PYNETDICOM") + +accepted_transfer_syntaxes = [ + '1.2.840.10008.1.2', # Implicit VR Little Endian + '1.2.840.10008.1.2.1', # Explicit VR Little Endian + '1.2.840.10008.1.2.2', # Explicit VR Big Endian + '1.2.840.10008.1.2.4.50', # JPEG Baseline (Process 1) + '1.2.840.10008.1.2.4.70', # JPEG Lossless, Non-Hierarchical (Process 14) +] + +# # Add the supported presentation contexts (Storage SCU) +# ae.supported_contexts = StoragePresentationContexts + +# # Accept the association requestor's proposed SCP role in the +# # SCP/SCU Role Selection Negotiation items +# for cx in ae.supported_contexts: +# cx.scp_role = True +# cx.scu_role = False + +# # Add a supported presentation context (QR Get SCP) +ae.add_supported_context(PatientRootQueryRetrieveInformationModelGet) +ae.add_supported_context(StudyRootQueryRetrieveInformationModelGet) +# ae.add_supported_context(MRImageStorage, accepted_transfer_syntaxes, scu_role=True, scp_role=True) +# ae.add_supported_context(CTImageStorage, accepted_transfer_syntaxes, scu_role=True, scp_role=True) + + +for context in AllStoragePresentationContexts: + ae.add_supported_context(context.abstract_syntax, ImplicitVRLittleEndian) + +# Start listening for incoming association requests +ae.start_server(("0.0.0.0", 11112), evt_handlers=handlers) \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NewTests/CGet/test_cget.py Tue Jan 21 18:50:03 2025 +0100 @@ -0,0 +1,69 @@ +import unittest +import time +import os +import threading +from helpers import OrthancTestCase, Helpers + +from orthanc_api_client import OrthancApiClient, ChangeType +from orthanc_api_client import helpers as OrthancHelpers + +import pathlib +import subprocess +import glob +here = pathlib.Path(__file__).parent.resolve() + +class TestCGet(OrthancTestCase): + + @classmethod + def cleanup(cls): + os.chdir(here) + print("Cleaning old compose") + subprocesss_env = os.environ.copy() + subprocesss_env["ORTHANC_IMAGE_UNDER_TESTS"] = Helpers.orthanc_under_tests_docker_image + subprocess.run(["docker", "compose", "-f", "docker-compose-c-get.yml", "down", "-v", "--remove-orphans"], + env=subprocesss_env, check=True) + + @classmethod + def compose_up(cls): + # print("Pullling containers") + # subprocesss_env = os.environ.copy() + # subprocesss_env["ORTHANC_IMAGE_UNDER_TESTS"] = Helpers.orthanc_under_tests_docker_image + # subprocess.run(["docker", "compose", "-f", "docker-compose-transfers-concurrency.yml", "pull"], + # env=subprocesss_env, check=True) + + print("Compose up") + subprocesss_env = os.environ.copy() + subprocesss_env["ORTHANC_IMAGE_UNDER_TESTS"] = Helpers.orthanc_under_tests_docker_image + subprocess.run(["docker", "compose", "-f", "docker-compose-c-get.yml", "up", "-d"], + env=subprocesss_env, check=True) + + @classmethod + def setUpClass(cls): + cls.cleanup() + cls.compose_up() + + @classmethod + def tearDownClass(cls): + cls.cleanup() + pass + + def clean_start(self): + oa = OrthancApiClient("http://localhost:8072") + ob = OrthancApiClient("http://localhost:8073") + + oa.wait_started() + ob.wait_started() + + oa.delete_all_content() + ob.delete_all_content() + + return oa, ob + + def test_cget(self): + + oa, ob = self.clean_start() + + instances_ids = ob.upload_folder( here / "../../Database/Brainix") + + oa.modalities.get_study(from_modality='b', dicom_id='2.16.840.1.113669.632.20.1211.10000357775') + self.assertEqual(len(instances_ids), len(oa.instances.get_all_ids()))
--- a/NewTests/Concurrency/test_transfer.py Tue Jan 21 18:48:59 2025 +0100 +++ b/NewTests/Concurrency/test_transfer.py Tue Jan 21 18:50:03 2025 +0100 @@ -45,7 +45,7 @@ @classmethod def tearDownClass(cls): - #cls.cleanup() + cls.cleanup() pass def clean_start(self):
--- a/NewTests/README Tue Jan 21 18:48:59 2025 +0100 +++ b/NewTests/README Tue Jan 21 18:50:03 2025 +0100 @@ -197,7 +197,7 @@ Read Only PG: --------------- +------------ Run the Read Only tests with your locally build version and break before execution to allow you to start your debugger. @@ -212,4 +212,12 @@ python3 NewTests/main.py --pattern=ReadOnly.test_readonly_pg.TestReadOnlyPG.* \ --orthanc_under_tests_docker_image=orthancteam/orthanc:current \ - --orthanc_under_tests_http_port=8043 \ No newline at end of file + --orthanc_under_tests_http_port=8043 + +C-Get: +----- + +with Docker: + +python3 NewTests/main.py --pattern=CGet.test_cget.TestCGet.* \ + --orthanc_under_tests_docker_image=orthancteam/orthanc-pre-release:2025.01.20 \ No newline at end of file