changeset 820:ae32a816cbe4 attach-custom-data

fix storage tests
author Alain Mazy <am@orthanc.team>
date Tue, 27 May 2025 16:20:18 +0200 (5 days ago)
parents 6fb7f40a9505
children cc4f3fbcd075
files NewTests/AdvancedStorage/test_advanced_storage.py NewTests/helpers.py
diffstat 2 files changed, 84 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/NewTests/AdvancedStorage/test_advanced_storage.py	Mon May 26 18:57:37 2025 +0200
+++ b/NewTests/AdvancedStorage/test_advanced_storage.py	Tue May 27 16:20:18 2025 +0200
@@ -24,7 +24,7 @@
     @classmethod
     def terminate(cls):
 
-        if Helpers.is_docker():
+        if Helpers.db == DB.PG:
             subprocess.run(["docker", "rm", "-f", "pg-server"])
 
 
@@ -64,14 +64,15 @@
 
         print(f'-------------- preparing {test_name} tests')
 
+        if Helpers.is_docker():
+            cls.create_docker_network(network_name)
+
         if Helpers.db == DB.PG:
             # launch the docker PG server
             print('--------------- launching PostgreSQL server ------------------')
 
-            if Helpers.is_docker():
-                # delete previous container if any
-                subprocess.run(["docker", "rm", "-f", "pg-server"])
-                cls.create_docker_network(network_name)
+            # delete previous container if any
+            subprocess.run(["docker", "rm", "-f", "pg-server"])
 
             pg_cmd = [            
                 "docker", "run", "--rm", 
@@ -82,6 +83,7 @@
             
             if Helpers.is_docker():
                 pg_cmd.extend(["--network", network_name])
+
             pg_cmd.append("postgres:15")
 
             cls.pg_service_process = subprocess.Popen(pg_cmd)
@@ -114,11 +116,22 @@
         cls.kill_orthanc()
         time.sleep(3)
 
-        shutil.rmtree('/tmp/indexed-files-a', ignore_errors=True)
-        shutil.rmtree('/tmp/indexed-files-b', ignore_errors=True)
+        # the path seen by the test
+        cls.base_test_storage_path = cls.get_storage_path(storage_name=cls._storage_name) + '/'
 
-        pathlib.Path('/tmp/indexed-files-a').mkdir(parents=True, exist_ok=True)
-        pathlib.Path('/tmp/indexed-files-b').mkdir(parents=True, exist_ok=True)
+        # the path seen by orthanc
+        if Helpers.is_docker():
+            cls.base_orthanc_storage_path = "/var/lib/orthanc/db/"
+        else:
+            cls.base_orthanc_storage_path = cls.base_test_storage_path
+
+        shutil.rmtree(cls.base_test_storage_path + 'indexed-files-a', ignore_errors=True)
+        shutil.rmtree(cls.base_test_storage_path + 'indexed-files-b', ignore_errors=True)
+        shutil.rmtree(cls.base_test_storage_path + 'adopt-files', ignore_errors=True)
+
+        pathlib.Path(cls.base_test_storage_path + 'indexed-files-a').mkdir(parents=True, exist_ok=True)
+        pathlib.Path(cls.base_test_storage_path + 'indexed-files-b').mkdir(parents=True, exist_ok=True)
+        pathlib.Path(cls.base_test_storage_path + 'adopt-files').mkdir(parents=True, exist_ok=True)
 
         config = { 
             db_config_key : db_config_content,
@@ -130,8 +143,8 @@
                 "MaxPathLength": 512,
                 "MultipleStorages": {
                     "Storages" : {
-                        "a" : cls.get_storage_path(cls._storage_name) + "/storage-a",
-                        "b" : cls.get_storage_path(cls._storage_name) + "/storage-b"
+                        "a" : cls.base_orthanc_storage_path + "storage-a",
+                        "b" : cls.base_orthanc_storage_path + "storage-b"
                     },
                     "CurrentWriteStorage": "b"
                 },
@@ -139,8 +152,8 @@
                 "Indexer" : {
                     "Enable": True,
                     "Folders": [
-                        "/tmp/indexed-files-a/",
-                        "/tmp/indexed-files-b/"
+                        cls.base_orthanc_storage_path + "indexed-files-a/",
+                        cls.base_orthanc_storage_path + "indexed-files-b/"
                     ],
                     "Interval": 1
                 },
@@ -174,9 +187,16 @@
         cls.o = OrthancApiClient(cls.o._root_url)
         cls.o.wait_started()
 
+    def check_file_exists(self, orthanc_path):
+        if Helpers.is_docker():
+            orthanc_path = orthanc_path.replace("/var/lib/orthanc/db", self.get_storage_path(self._storage_name))
+        return os.path.exists(orthanc_path)
+
     def test_can_read_files_saved_without_plugin(self):
         info0 = self.o.get_json(endpoint=f"/instances/{self.instances_ids_before[0]}/attachments/dicom/info")
-        self.assertTrue(info0['Path'].startswith(self.get_storage_path(self._storage_name)))
+        if not Helpers.is_docker():
+            self.assertTrue(info0['Path'].startswith(self.get_storage_path(self._storage_name)))
+        # pprint.pprint(info0)
         self.assertFalse(info0['Path'].endswith('.dcm'))
         self.assertFalse(info0['IsAdopted'])
         self.assertFalse('IsIndexed' in info0 and info0['IsIndexed'])
@@ -195,22 +215,26 @@
         info_after_move = self.o.get_json(endpoint=f"/instances/{self.instances_ids_before[0]}/attachments/dicom/info")
         self.assertIn('storage-a', info_after_move['Path'])
         self.assertEqual("a", info_after_move['StorageId'])
-        self.assertTrue(os.path.exists(info_after_move['Path']))
-        
+        # self.assertTrue(os.path.exists(info_after_move['Path']))
+        self.assertTrue(self.check_file_exists(info_after_move['Path']))
+
         self.wait_until_no_more_pending_deletion_files()
-        self.assertFalse(os.path.exists(info0['Path']))
+        # self.assertFalse(os.path.exists(info0['Path']))
+        self.assertFalse(self.check_file_exists(info0['Path']))
 
         # now delete the instance 0 (the one that has been moved) 
         self.o.instances.delete(orthanc_id=self.instances_ids_before[0])
         
         self.wait_until_no_more_pending_deletion_files()
-        self.assertFalse(os.path.exists(info_after_move['Path']))
+        # self.assertFalse(os.path.exists(info_after_move['Path']))
+        self.assertFalse(self.check_file_exists(info_after_move['Path']))
 
         # now delete the instance 1 (that has NOT been moved) 
         self.o.instances.delete(orthanc_id=self.instances_ids_before[1])
         
         self.wait_until_no_more_pending_deletion_files()
-        self.assertFalse(os.path.exists(info1['Path']))
+        # self.assertFalse(os.path.exists(info1['Path']))
+        self.assertFalse(self.check_file_exists(info1['Path']))
 
 
     def test_basic(self):
@@ -221,7 +245,8 @@
         info = self.o.get_json(endpoint=f"/instances/{uploaded_instances_ids[0]}/attachments/dicom/info")
         
         self.assertIn('storage-b/2007/01/01/1.2.840.113619.2.176.2025.1499492.7391.1171285944.390 - ozp00SjY2xG/1.2.840.113619.2.176.2025.1499492.7391.1171285944.388/000001 - ', info['Path'])
-        self.assertTrue(os.path.exists(info['Path']))
+        # self.assertTrue(os.path.exists(info['Path']))
+        self.assertTrue(self.check_file_exists(info['Path']))
         self.assertTrue(info['Path'].endswith(".dcm"))
         self.assertFalse(info['IsAdopted'])
         self.assertFalse(info['IsIndexed'])
@@ -236,6 +261,8 @@
         OrthancHelpers.wait_until(lambda: self.has_no_more_pending_deletion_files(), timeout=10, polling_interval=1)
 
     def test_move_storage(self):
+
+
         # upload a single file
         uploaded_instances_ids = self.o.upload_file(here / "../../Database/Knix/Loc/IM-0001-0001.dcm")
 
@@ -243,7 +270,8 @@
         info_before_move = self.o.get_json(endpoint=f"/instances/{uploaded_instances_ids[0]}/attachments/dicom/info")
         self.assertIn('storage-b', info_before_move['Path'])
         self.assertEqual("b", info_before_move['StorageId'])
-        self.assertTrue(os.path.exists(info_before_move['Path']))
+        # self.assertTrue(os.path.exists(info_before_move['Path']))
+        self.assertTrue(self.check_file_exists(info_before_move['Path']))
 
         # move it to storage A
         self.o.post(endpoint="/plugins/advanced-storage/move-storage",
@@ -256,10 +284,12 @@
         info_after_move = self.o.get_json(endpoint=f"/instances/{uploaded_instances_ids[0]}/attachments/dicom/info")
         self.assertIn('storage-a', info_after_move['Path'])
         self.assertEqual("a", info_after_move['StorageId'])
-        self.assertTrue(os.path.exists(info_after_move['Path']))
+        # self.assertTrue(os.path.exists(info_after_move['Path']))
+        self.assertTrue(self.check_file_exists(info_after_move['Path']))
 
         self.wait_until_no_more_pending_deletion_files()
-        self.assertFalse(os.path.exists(info_before_move['Path']))
+        # self.assertFalse(os.path.exists(info_before_move['Path']))
+        self.assertFalse(self.check_file_exists(info_before_move['Path']))
 
         # move it to back to storage B
         self.o.post(endpoint="/plugins/advanced-storage/move-storage",
@@ -272,21 +302,27 @@
         info_after_move2 = self.o.get_json(endpoint=f"/instances/{uploaded_instances_ids[0]}/attachments/dicom/info")
         self.assertIn('storage-b', info_after_move2['Path'])
         self.assertEqual("b", info_after_move2['StorageId'])
-        self.assertTrue(os.path.exists(info_after_move2['Path']))
+        # self.assertTrue(os.path.exists(info_after_move2['Path']))
+        self.assertTrue(self.check_file_exists(info_after_move2['Path']))
 
         self.wait_until_no_more_pending_deletion_files()
-        self.assertFalse(os.path.exists(info_after_move['Path']))
+        # self.assertFalse(os.path.exists(info_after_move['Path']))
+        self.assertFalse(self.check_file_exists(info_after_move['Path']))
+
+    def test_adopt_abandon(self):
+
+        shutil.copy(here / "../../Database/Beaufix/IM-0001-0001.dcm", self.base_test_storage_path + "adopt-files/")
+        shutil.copy(here / "../../Database/Beaufix/IM-0001-0002.dcm", self.base_test_storage_path + "adopt-files/")
 
 
-    def test_adopt_abandon(self):
         # adopt a file
         r1 = self.o.post(endpoint="/plugins/advanced-storage/adopt-instance",
                         json={
-                            "Path": str(here / "../../Database/Beaufix/IM-0001-0001.dcm")
+                            "Path": self.base_orthanc_storage_path + "adopt-files/IM-0001-0001.dcm"
                         }).json()
         r2 = self.o.post(endpoint="/plugins/advanced-storage/adopt-instance",
                         json={
-                            "Path": str(here / "../../Database/Beaufix/IM-0001-0002.dcm")
+                            "Path": self.base_orthanc_storage_path + "adopt-files/IM-0001-0002.dcm"
                         }).json()
 
         # pprint.pprint(r1)
@@ -297,7 +333,8 @@
         self.assertNotIn('StorageId', info1)
         self.assertTrue(info1['IsAdopted'])
         self.assertFalse(info1['IsIndexed'])
-        self.assertTrue(os.path.exists(info1['Path']))
+        # self.assertTrue(os.path.exists(info1['Path']))
+        self.assertTrue(self.check_file_exists(info1['Path']))
         self.assertEqual(r1['AttachmentUuid'], info1['Uuid'])
 
         info2 = self.o.get_json(endpoint=f"/instances/{r2['InstanceId']}/attachments/dicom/info")
@@ -313,27 +350,29 @@
         # delete an adopted file -> the file shall not be removed
         self.o.instances.delete(orthanc_id=r1['InstanceId'])
         self.assertNotIn(r1['InstanceId'], self.o.instances.get_all_ids())
-        self.assertTrue(os.path.exists(info1['Path']))
+        # self.assertTrue(os.path.exists(info1['Path']))
+        self.assertTrue(self.check_file_exists(info1['Path']))
 
         # abandon an adopted file -> the file shall not be removed (it shall be equivalent to a delete)
         self.o.post(endpoint="/plugins/advanced-storage/abandon-instance",
                     json={
-                        "Path": str(here / "../../Database/Beaufix/IM-0001-0002.dcm")
+                        "Path": self.base_orthanc_storage_path + "adopt-files/IM-0001-0002.dcm"
                     })
         self.assertNotIn(r2['InstanceId'], self.o.instances.get_all_ids())
-        self.assertTrue(os.path.exists(info2['Path']))
+        # self.assertTrue(os.path.exists(info2['Path']))
+        self.assertTrue(self.check_file_exists(info2['Path']))
 
     def test_indexer(self):
         # add 2 files to the 2 indexed folders
-        shutil.copy(here / "../../Database/Comunix/Ct/IM-0001-0001.dcm", "/tmp/indexed-files-a/")
-        shutil.copy(here / "../../Database/Comunix/Pet/IM-0001-0001.dcm", "/tmp/indexed-files-b/")
+        shutil.copy(here / "../../Database/Comunix/Ct/IM-0001-0001.dcm", self.base_test_storage_path + "indexed-files-a/")
+        shutil.copy(here / "../../Database/Comunix/Pet/IM-0001-0001.dcm", self.base_test_storage_path + "indexed-files-b/")
 
         # wait for the files to be indexed
-        time.sleep(3)
+        time.sleep(5)
 
         # check that the study has been indexed
         studies = self.o.studies.find(query={"PatientName": "COMUNIX"})
-        self.assertEqual(2, len(studies[0].series))
+        self.assertEqual(2, len(self.o.studies.get_series_ids(studies[0].orthanc_id)))
         
         instances_ids = self.o.studies.get_instances_ids(studies[0].orthanc_id)
         info1 = self.o.get_json(endpoint=f"/instances/{instances_ids[0]}/attachments/dicom/info")
@@ -343,11 +382,11 @@
         self.assertTrue(info1['IsAdopted'])
 
         # remove one of the file from the indexed folders -> it shall disappear from Orthanc
-        os.remove(info1['Path'])
+        os.remove(self.base_test_storage_path + "indexed-files-b/IM-0001-0001.dcm")
 
-        time.sleep(3)
+        time.sleep(5)
         studies = self.o.studies.find(query={"PatientName": "COMUNIX"})
-        self.assertEqual(1, len(studies[0].series))
+        self.assertEqual(1, len(self.o.studies.get_series_ids(studies[0].orthanc_id)))
 
         # delete the other file from the Orthanc API -> the file shall not be deleted since it is not owned by Orthanc
         # and it shall not be indexed anymore ...
@@ -357,6 +396,6 @@
         
         studies = self.o.studies.find(query={"PatientName": "COMUNIX"})
         self.assertEqual(0, len(studies))
-        self.assertTrue(os.path.exists(info2['Path']))
+        # self.assertTrue(os.path.exists(info2['Path']))
+        self.assertTrue(os.path.exists(self.base_test_storage_path + "indexed-files-a/IM-0001-0001.dcm"))
 
-
--- a/NewTests/helpers.py	Mon May 26 18:57:37 2025 +0200
+++ b/NewTests/helpers.py	Tue May 27 16:20:18 2025 +0200
@@ -190,10 +190,12 @@
                     "-v", f"{storage_path}:/var/lib/orthanc/db/",
                     "--name", "storage-cleanup",
                     "debian:12-slim",
-                    "rm", "-rf", "/var/lib/orthanc/db/*"
+                    "bash", "-c", "rm -rf /var/lib/orthanc/db/*"
                 ]
+            subprocess.run(cmd, check=True)
+            
+            pathlib.Path(storage_path).mkdir(parents=True, exist_ok=True)
 
-            subprocess.run(cmd, check=True)
 
     @classmethod
     def is_storage_empty(cls, storage_name: str):