# HG changeset patch # User Alain Mazy # Date 1707906340 -3600 # Node ID 543e372d22657852b9ffef247aeb4ed9c467d9e4 # Parent 3bb4b25890300c697cc55297ff274473e89aecfe added a PG max storage test diff -r 3bb4b2589030 -r 543e372d2265 NewTests/Concurrency/test_concurrency.py --- a/NewTests/Concurrency/test_concurrency.py Wed Feb 07 11:43:32 2024 +0100 +++ b/NewTests/Concurrency/test_concurrency.py Wed Feb 14 11:25:40 2024 +0100 @@ -7,8 +7,6 @@ from orthanc_api_client import OrthancApiClient, ChangeType from orthanc_api_client import helpers as OrthancHelpers -from orthanc_tools import OrthancTestDbPopulator - import pathlib import subprocess import glob diff -r 3bb4b2589030 -r 543e372d2265 NewTests/MaxStorage/__init__.py diff -r 3bb4b2589030 -r 543e372d2265 NewTests/MaxStorage/test_max_storage_pg.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NewTests/MaxStorage/test_max_storage_pg.py Wed Feb 14 11:25:40 2024 +0100 @@ -0,0 +1,134 @@ +import unittest +import time +import os +import threading +from helpers import OrthancTestCase, Helpers + +from orthanc_api_client import OrthancApiClient, ChangeType +from orthanc_api_client.exceptions import HttpError +from orthanc_api_client import helpers as OrthancHelpers + +from orthanc_tools import OrthancTestDbPopulator + +import pathlib +import subprocess +import glob +here = pathlib.Path(__file__).parent.resolve() + + +class TestMaxStoragePG(OrthancTestCase): + + @classmethod + def terminate(cls): + + if Helpers.is_docker(): + subprocess.run(["docker", "rm", "-f", "pg-server"]) + else: + cls.pg_service_process.terminate() + + + @classmethod + def prepare(cls): + test_name = "MaxStoragePG" + cls._storage_name = "max-storage-pg" + network_name = "max-storage-pg" + + print(f'-------------- preparing {test_name} tests') + + cls.clear_storage(storage_name=cls._storage_name) + + pg_hostname = "localhost" + if Helpers.is_docker(): + pg_hostname = "pg-server" + cls.create_docker_network(network_name) + + config = { + "PostgreSQL" : { + "EnableStorage": False, + "EnableIndex": True, + "Host": pg_hostname, + "Port": 5432, + "Database": "postgres", + "Username": "postgres", + "Password": "postgres", + "IndexConnectionsCount": 10, + "MaximumConnectionRetries" : 2000, + "ConnectionRetryInterval" : 5, + "TransactionMode": "ReadCommitted", + #"TransactionMode": "Serializable", + "EnableVerboseLogs": True + }, + "AuthenticationEnabled": False, + "OverwriteInstances": True, + "MaximumStorageSize": 1, + "MaximumStorageMode": "Recycle" + # "MaximumPatientCount": 1, + # "MaximumStorageMode": "Reject" + } + + config_path = cls.generate_configuration( + config_name=f"{test_name}", + storage_name=cls._storage_name, + config=config, + plugins=Helpers.plugins + ) + + # launch the docker PG server + print('--------------- launching PostgreSQL server ------------------') + + pg_cmd = [ + "docker", "run", "--rm", + "-p", "5432:5432", + "--name", "pg-server", + "--env", "POSTGRES_HOST_AUTH_METHOD=trust" + ] + + if Helpers.is_docker(): + pg_cmd.extend(["--network", network_name]) + pg_cmd.append("postgres:15") + + cls.pg_service_process = subprocess.Popen(pg_cmd) + time.sleep(5) + + if Helpers.break_after_preparation: + print(f"++++ It is now time to start your Orthanc under tests with configuration file '{config_path}' +++++") + input("Press Enter to continue") + else: + cls.launch_orthanc_under_tests( + config_name=f"{test_name}", + storage_name=cls._storage_name, + config=config, + plugins=Helpers.plugins, + docker_network=network_name + ) + + cls.o = OrthancApiClient(cls.o._root_url) + cls.o.wait_started() + cls.o.delete_all_content() + + + def test_upload(self): + self.o.delete_all_content() + self.clear_storage(storage_name=self._storage_name) + + uploaded_instances_ids = [] + counter = 0 + # upload 10 images of 500x500, since the MaximumStorageSize is 1MB, only 2 of them should remain in the storage + for i in range(0, 10): + counter += 1 + dicom_file = OrthancHelpers.generate_test_dicom_file(width=500, height=500, + tags = { + "PatientID" : f"{i}", + "StudyInstanceUID" : f"{i}", + "SeriesInstanceUID" : f"{i}.{counter%10}" + }) + try: + uploaded_instances_ids.extend(self.o.upload(dicom_file)) + except HttpError as er: + if er.http_status_code == 507: + pass # ignore + + # some instances have been discarded + self.assertLess(len(self.o.instances.get_all_ids()), 10) + self.assertLess(len(self.o.patients.get_all_ids()), 10) + self.assertLess(self.o.get_statistics().total_disk_size, 1*1024*1024) diff -r 3bb4b2589030 -r 543e372d2265 NewTests/MaxStorage/test_max_storage_reject.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NewTests/MaxStorage/test_max_storage_reject.py Wed Feb 14 11:25:40 2024 +0100 @@ -0,0 +1,127 @@ +import unittest +import time +import subprocess +import pprint +import os +from helpers import OrthancTestCase, Helpers + +from orthanc_api_client import OrthancApiClient, generate_test_dicom_file +from orthanc_api_client import exceptions as orthanc_exceptions + +import pathlib +here = pathlib.Path(__file__).parent.resolve() + + +def count_files_in_storage(path): + all_files = [] + for root, dirs, files in os.walk(path): + for file in files: + if len(file) == 36: + all_files.append(file) + + return len(all_files) + + +class TestMaxStorageReject(OrthancTestCase): + + @classmethod + def prepare(cls): + test_name = "MaxStorageReject" + storage_name = "max_storage_reject" + + cls.clear_storage(storage_name=storage_name) + + config_path = cls.generate_configuration( + config_name=f"{test_name}_under_test", + storage_name=storage_name, + config={ + "MaximumPatientCount": 2, + "MaximumStorageMode": "Reject" + }, + plugins=Helpers.plugins + ) + + print(f'-------------- prepared {test_name} tests') + if Helpers.break_after_preparation: + print(f"++++ It is now time to start your Orthanc under tests with configuration file '{config_path}' +++++") + input("Press Enter to continue") + else: + print(f'-------------- launching {test_name} tests') + cls.launch_orthanc_under_tests( + config_path=config_path, + config_name=f"{test_name}_under_test", + storage_name=storage_name, + plugins=Helpers.plugins + ) + + print('-------------- waiting for orthanc-under-tests to be available') + cls.o.wait_started() + + + def test_upload_3_patients_rest_api(self): + + if self.o.get_system()["ApiVersion"] > 20: # from Orthanc 1.12.1 + self.o.delete_all_content() + + # make sure the 3rd patient does not make it into the storage (through the Rest API) + self.o.upload_file(here / "../../Database/Brainix/Flair/IM-0001-0001.dcm") + self.o.upload_file(here / "../../Database/Knix/Loc/IM-0001-0001.dcm") + with self.assertRaises(orthanc_exceptions.HttpError) as ctx: + self.o.upload_file(here / "../../Database/Phenix/IM-0001-0001.dcm") + self.assertEqual(507, ctx.exception.http_status_code) + self.assertEqual(2, len(self.o.studies.get_all_ids())) + self.assertEqual(2, count_files_in_storage(self.get_storage_path("max_storage_reject"))) + + def upload_with_store_scu(self, path): + subprocess.check_call([Helpers.find_executable('storescu'), + "-xs", + Helpers.get_orthanc_ip(), + str(Helpers.get_orthanc_dicom_port()), + path]) + + def test_upload_3_patients_c_store(self): + + if self.o.get_system()["ApiVersion"] > 20: # from Orthanc 1.12.1 + self.o.delete_all_content() + + # make sure the 3rd patient does not make it into the storage (through StoreSCU) + self.upload_with_store_scu(here / "../../Database/Brainix/Flair/IM-0001-0001.dcm") + self.upload_with_store_scu(here / "../../Database/Knix/Loc/IM-0001-0001.dcm") + with self.assertRaises(subprocess.CalledProcessError) as ctx: + self.upload_with_store_scu(here / "../../Database/Phenix/IM-0001-0001.dcm") + self.assertEqual(2, len(self.o.studies.get_all_ids())) + self.assertEqual(2, count_files_in_storage(self.get_storage_path("max_storage_reject"))) + + def test_upload_3_patients_dicomweb(self): + + if self.o.get_system()["ApiVersion"] > 20: # from Orthanc 1.12.1 + self.o.delete_all_content() + + # make sure the 3rd patient does not make it into the storage (through DicomWeb) + self.o.upload_files_dicom_web([here / "../../Database/Brainix/Flair/IM-0001-0001.dcm"]) + self.o.upload_files_dicom_web([here / "../../Database/Knix/Loc/IM-0001-0001.dcm"]) + + with self.assertRaises(orthanc_exceptions.HttpError) as ctx: + self.o.upload_files_dicom_web([here / "../../Database/Phenix/IM-0001-0001.dcm"]) + self.assertEqual(400, ctx.exception.http_status_code) + + self.assertEqual(2, len(self.o.studies.get_all_ids())) + self.assertEqual(2, count_files_in_storage(self.get_storage_path("max_storage_reject"))) + + def test_upload_3_patients_dicomweb_in_one_query(self): + + if self.o.get_system()["ApiVersion"] > 20: # from Orthanc 1.12.1 + self.o.delete_all_content() + + # make sure the 3rd patient does not make it into the storage (through DicomWeb) + r = self.o.upload_files_dicom_web([ + here / "../../Database/Brainix/Flair/IM-0001-0001.dcm", + here / "../../Database/Knix/Loc/IM-0001-0001.dcm", + here / "../../Database/Phenix/IM-0001-0001.dcm" + ]) + + # pprint.pprint(r) + self.assertEqual(2, len(self.o.studies.get_all_ids())) + self.assertIn('00081198', r) + self.assertEqual(0xA700, r['00081198']['Value'][0]['00081197']['Value'][0]) # one failed instance with out-of-resource status + self.assertEqual(2, count_files_in_storage(self.get_storage_path("max_storage_reject"))) diff -r 3bb4b2589030 -r 543e372d2265 NewTests/MaxStorageReject/__init__.py diff -r 3bb4b2589030 -r 543e372d2265 NewTests/MaxStorageReject/test_max_storage_reject.py --- a/NewTests/MaxStorageReject/test_max_storage_reject.py Wed Feb 07 11:43:32 2024 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -import unittest -import time -import subprocess -import pprint -import os -from helpers import OrthancTestCase, Helpers - -from orthanc_api_client import OrthancApiClient, generate_test_dicom_file -from orthanc_api_client import exceptions as orthanc_exceptions - -import pathlib -here = pathlib.Path(__file__).parent.resolve() - - -def count_files_in_storage(path): - all_files = [] - for root, dirs, files in os.walk(path): - for file in files: - if len(file) == 36: - all_files.append(file) - - return len(all_files) - - -class TestMaxStorageReject(OrthancTestCase): - - @classmethod - def prepare(cls): - test_name = "MaxStorageReject" - storage_name = "max_storage_reject" - - cls.clear_storage(storage_name=storage_name) - - config_path = cls.generate_configuration( - config_name=f"{test_name}_under_test", - storage_name=storage_name, - config={ - "MaximumPatientCount": 2, - "MaximumStorageMode": "Reject" - }, - plugins=Helpers.plugins - ) - - print(f'-------------- prepared {test_name} tests') - if Helpers.break_after_preparation: - print(f"++++ It is now time to start your Orthanc under tests with configuration file '{config_path}' +++++") - input("Press Enter to continue") - else: - print(f'-------------- launching {test_name} tests') - cls.launch_orthanc_under_tests( - config_path=config_path, - config_name=f"{test_name}_under_test", - storage_name=storage_name, - plugins=Helpers.plugins - ) - - print('-------------- waiting for orthanc-under-tests to be available') - cls.o.wait_started() - - - def test_upload_3_patients_rest_api(self): - - if self.o.get_system()["ApiVersion"] > 20: # from Orthanc 1.12.1 - self.o.delete_all_content() - - # make sure the 3rd patient does not make it into the storage (through the Rest API) - self.o.upload_file(here / "../../Database/Brainix/Flair/IM-0001-0001.dcm") - self.o.upload_file(here / "../../Database/Knix/Loc/IM-0001-0001.dcm") - with self.assertRaises(orthanc_exceptions.HttpError) as ctx: - self.o.upload_file(here / "../../Database/Phenix/IM-0001-0001.dcm") - self.assertEqual(507, ctx.exception.http_status_code) - self.assertEqual(2, len(self.o.studies.get_all_ids())) - self.assertEqual(2, count_files_in_storage(self.get_storage_path("max_storage_reject"))) - - def upload_with_store_scu(self, path): - subprocess.check_call([Helpers.find_executable('storescu'), - "-xs", - Helpers.get_orthanc_ip(), - str(Helpers.get_orthanc_dicom_port()), - path]) - - def test_upload_3_patients_c_store(self): - - if self.o.get_system()["ApiVersion"] > 20: # from Orthanc 1.12.1 - self.o.delete_all_content() - - # make sure the 3rd patient does not make it into the storage (through StoreSCU) - self.upload_with_store_scu(here / "../../Database/Brainix/Flair/IM-0001-0001.dcm") - self.upload_with_store_scu(here / "../../Database/Knix/Loc/IM-0001-0001.dcm") - with self.assertRaises(subprocess.CalledProcessError) as ctx: - self.upload_with_store_scu(here / "../../Database/Phenix/IM-0001-0001.dcm") - self.assertEqual(2, len(self.o.studies.get_all_ids())) - self.assertEqual(2, count_files_in_storage(self.get_storage_path("max_storage_reject"))) - - def test_upload_3_patients_dicomweb(self): - - if self.o.get_system()["ApiVersion"] > 20: # from Orthanc 1.12.1 - self.o.delete_all_content() - - # make sure the 3rd patient does not make it into the storage (through DicomWeb) - self.o.upload_files_dicom_web([here / "../../Database/Brainix/Flair/IM-0001-0001.dcm"]) - self.o.upload_files_dicom_web([here / "../../Database/Knix/Loc/IM-0001-0001.dcm"]) - - with self.assertRaises(orthanc_exceptions.HttpError) as ctx: - self.o.upload_files_dicom_web([here / "../../Database/Phenix/IM-0001-0001.dcm"]) - self.assertEqual(400, ctx.exception.http_status_code) - - self.assertEqual(2, len(self.o.studies.get_all_ids())) - self.assertEqual(2, count_files_in_storage(self.get_storage_path("max_storage_reject"))) - - def test_upload_3_patients_dicomweb_in_one_query(self): - - if self.o.get_system()["ApiVersion"] > 20: # from Orthanc 1.12.1 - self.o.delete_all_content() - - # make sure the 3rd patient does not make it into the storage (through DicomWeb) - r = self.o.upload_files_dicom_web([ - here / "../../Database/Brainix/Flair/IM-0001-0001.dcm", - here / "../../Database/Knix/Loc/IM-0001-0001.dcm", - here / "../../Database/Phenix/IM-0001-0001.dcm" - ]) - - # pprint.pprint(r) - self.assertEqual(2, len(self.o.studies.get_all_ids())) - self.assertIn('00081198', r) - self.assertEqual(0xA700, r['00081198']['Value'][0]['00081197']['Value'][0]) # one failed instance with out-of-resource status - self.assertEqual(2, count_files_in_storage(self.get_storage_path("max_storage_reject"))) diff -r 3bb4b2589030 -r 543e372d2265 NewTests/README --- a/NewTests/README Wed Feb 07 11:43:32 2024 +0100 +++ b/NewTests/README Wed Feb 14 11:25:40 2024 +0100 @@ -120,18 +120,26 @@ - execute tests -MaxStorageReject: ------------------- +MaxStorage: +---------- -Run the MaxStorageReject tests with your locally build version and break before and after preparation +Run the MaxStorage tests with your locally build version and break before and after preparation and execution to allow you to start your debugger. -python3 NewTests/main.py --pattern=MaxStorageReject.test_max_storage_reject.TestMaxStorageReject.* \ +python3 NewTests/main.py --pattern=MaxStorage.test_max_storage_reject.TestMaxStorageReject.* \ --orthanc_under_tests_exe=/home/alain/o/build/orthanc/Orthanc \ --orthanc_under_tests_http_port=8043 \ --plugin=/home/alain/o/build/orthanc-dicomweb/libOrthancDicomWeb.so \ --break_after_preparation +python3 NewTests/main.py --pattern=MaxStorage.test_max_storage_pg.TestMaxStoragePG.* \ + --orthanc_under_tests_exe=/home/alain/o/build/orthanc/Orthanc \ + --orthanc_under_tests_http_port=8043 \ + --plugin=/home/alain/o/build/orthanc-dicomweb/libOrthancDicomWeb.so \ + --plugin=/home/alain/o/build/pg/libOrthancPostgreSQLIndex.so \ + --break_after_preparation + + Authorization: --------------