changeset 263:a2719263fd04

test_study_series_find_inconsistency
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 20 Feb 2020 19:58:30 +0100
parents 045a45c3f945
children 445f498bc1d4
files Database/Lua/HttpClient.lua GenerateConfigurationForTests.py Tests/Tests.py
diffstat 3 files changed, 221 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/Database/Lua/HttpClient.lua	Fri Feb 14 17:22:11 2020 +0100
+++ b/Database/Lua/HttpClient.lua	Thu Feb 20 19:58:30 2020 +0100
@@ -37,6 +37,9 @@
 -- Issue HttpDelete (juste make sure it is issued, we can't check the response)
 HttpDelete('http://httpbin.org/delete', httpHeaders)
 
+-- TODO Very strange: Since Orthanc 1.6.0, a timeout frequently occurs
+-- in curl at this point
+
 -- Issue HttpGet
 response = ParseJson(HttpGet('http://httpbin.org/get', httpHeaders))
 testSucceeded = testSucceeded and (response['headers']['Content-Type'] == 'application/json' and response['headers']['Toto'] == 'Tutu')
--- a/GenerateConfigurationForTests.py	Fri Feb 14 17:22:11 2020 +0100
+++ b/GenerateConfigurationForTests.py	Thu Feb 20 19:58:30 2020 +0100
@@ -132,6 +132,7 @@
 config['MediaArchiveSize'] = 1
 config['SaveJobs'] = False
 config['ExecuteLuaEnabled'] = True
+config['HttpTimeout'] = 2
 del config['KeepAlive']
 
 config['Dictionary'] = {
--- a/Tests/Tests.py	Fri Feb 14 17:22:11 2020 +0100
+++ b/Tests/Tests.py	Thu Feb 20 19:58:30 2020 +0100
@@ -4901,3 +4901,220 @@
         DoPut(_REMOTE, '/tools/log-level', original)
         
         
+    def test_study_series_find_inconsistency(self):
+        # https://groups.google.com/forum/#!topic/orthanc-users/bLv6Z11COy0
+
+        def CountAnswers(query):
+            a = DoPost(_REMOTE, 'modalities/self/query', query)
+            return len(DoGet(_REMOTE, '%s/answers' % a['Path']))
+
+        # This instance has "SeriesDescription" (0008,103e) tag, but no
+        # "ProtocolName" (0018,1030). Both of those tags are part of
+        # the "main DICOM tags" of Orthanc.
+        UploadInstance(_REMOTE, 'Issue137.dcm')
+
+        
+        self.assertEqual(1, CountAnswers({
+            'Level' : 'Study',
+        }))
+
+        self.assertEqual(1, CountAnswers({
+            'Level' : 'Series',
+        }))
+
+        
+        ##
+        ## "SeriesDescription" is present, and has VR "CS" => wildcard is allowed
+        ## http://dicom.nema.org/medical/dicom/2019e/output/chtml/part04/sect_C.2.2.2.4.html
+        ##
+
+        # At the study level, the "SeriesDescription" tag is not allowed, but
+        # is wiped out by the normalization
+        self.assertEqual(0, CountAnswers({
+            'Level' : 'Study',
+            'Query' : {
+                'SeriesDescription' : 'NOPE'
+            },
+            'Normalize' : False
+        }))
+        self.assertEqual(0, CountAnswers({
+            # This test fails on Orthanc <= 1.5.8
+            'Level' : 'Study',
+            'Query' : {
+                'SeriesDescription' : '*'  # Wildcard matching => no match, as the tag is absent
+            },
+            'Normalize' : False
+        }))
+        self.assertEqual(1, CountAnswers({
+            'Level' : 'Study',
+            'Query' : {
+                'SeriesDescription' : 'THIS^VALUE^IS^WIPED^OUT'
+            },
+            'Normalize' : True
+        }))
+        self.assertEqual(1, CountAnswers({
+            'Level' : 'Study',
+            'Query' : {
+                'SeriesDescription' : '*'  # Matches, as wiped out by the normalization
+            },
+            'Normalize' : True
+        }))
+
+        for normalize in [ True, False ]:
+            # At the series level, the "SeriesDescription" tag is allowed, and
+            # normalization has no effect
+
+            # "Universal matching" will match all entities, including
+            # those with the missing tag
+            # http://dicom.nema.org/medical/dicom/2019e/output/chtml/part04/sect_C.2.2.2.3.html
+            self.assertEqual(1, CountAnswers({
+                'Level' : 'Series',
+                'Query' : {
+                    'SeriesDescription' : ''  # Universal matching
+                },
+                'Normalize' : normalize,
+            }))
+            # "Universal matching" will match all entities, including
+            # those with the missing tag
+            # http://dicom.nema.org/medical/dicom/2019e/output/chtml/part04/sect_C.2.2.2.3.html
+            self.assertEqual(1, CountAnswers({
+                'Level' : 'Series',
+                'Query' : {
+                    'SeriesDescription' : '*'  # Wildcard matching
+                },
+                'Normalize' : normalize,
+            }))
+            self.assertEqual(1, CountAnswers({
+                'Level' : 'Series',
+                'Query' : {
+                    'SeriesDescription' : '*model*'  # The actual value is "STL model: intraop Report"
+                },
+                'Normalize' : normalize,
+            }))
+            self.assertEqual(0, CountAnswers({
+                'Level' : 'Series',
+                'Query' : {
+                    'SeriesDescription' : '*MISMATCHED^VALUE*'
+                },
+                'Normalize' : normalize,
+            }))
+
+            # Universal matching matches any instance, even if the
+            # query is at the study-level, and thus if "SeriesDescription"
+            # makes no sense
+            self.assertEqual(1, CountAnswers({
+                'Level' : 'Study',
+                'Query' : {
+                    'SeriesDescription' : ''  # Universal matching
+                },
+                'Normalize' : normalize,
+            }))
+        
+
+
+        ##
+        ## "ProtocolName" is absent, and has VR "CS" => wildcard is allowed
+        ##
+
+        # At the study level, the "ProtocolName" tag is not allowed, but
+        # is wiped out by the normalization
+        self.assertEqual(0, CountAnswers({
+            'Level' : 'Study',
+            'Query' : {
+                'ProtocolName' : 'NOPE'
+            },
+            'Normalize' : False
+        }))
+        self.assertEqual(0, CountAnswers({
+            'Level' : 'Study',
+            'Query' : {
+                'ProtocolName' : '*'  # Wildcard matching => no match, as the tag is absent
+            },
+            'Normalize' : False
+        }))
+        self.assertEqual(1, CountAnswers({
+            'Level' : 'Study',
+            'Query' : {
+                'ProtocolName' : 'THIS^VALUE^IS^WIPED^OUT'
+            },
+            'Normalize' : True
+        }))
+        self.assertEqual(1, CountAnswers({
+            'Level' : 'Study',
+            'Query' : {
+                'ProtocolName' : '*'  # Matches, as wiped out by the normalization
+            },
+            'Normalize' : True
+        }))
+
+        for normalize in [ True, False ]:
+            # At the series level, the "ProtocolName" tag is allowed, and
+            # normalization has no effect
+
+            self.assertEqual(1, CountAnswers({
+                'Level' : 'Series',
+                'Query' : {
+                    'ProtocolName' : ''  # Universal matching
+                },
+                'Normalize' : normalize,
+            }))
+            self.assertEqual(0, CountAnswers({
+                'Level' : 'Series',
+                'Query' : {
+                    'ProtocolName' : '*'  # Wildcard matching => no match, as the tag is absent
+                },
+                'Normalize' : normalize,
+            }))
+            self.assertEqual(0, CountAnswers({
+                'Level' : 'Series',
+                'Query' : {
+                    'ProtocolName' : '*MISMATCHED^VALUE*'
+                },
+                'Normalize' : normalize,
+            }))
+
+            self.assertEqual(1, CountAnswers({
+                'Level' : 'Study',
+                'Query' : {
+                    'ProtocolName' : '' # Universal matching
+                },
+                'Normalize' : normalize,
+            }))
+            
+
+        ##
+        ## "StudyInstanceUID" is present, and has VR "UI" => wildcard is not allowed
+        ##
+
+        for level in [ 'Study', 'Series' ] :
+            for normalize in [ True, False ]:
+                self.assertEqual(1, CountAnswers({
+                    'Level' : level,
+                    'Query' : {
+                        'StudyInstanceUID' : ''  # Universal matching
+                    },
+                    'Normalize' : normalize,
+                }))
+                self.assertEqual(0, CountAnswers({
+                    'Level' : level,
+                    'Query' : {
+                        'StudyInstanceUID' : 'MISMATCHED^VALUE'
+                    },
+                    'Normalize' : normalize,
+                }))
+                self.assertEqual(1, CountAnswers({
+                    'Level' : level,
+                    'Query' : {
+                        'StudyInstanceUID' : '4.5.6'  # This is the actual value
+                    },
+                    'Normalize' : normalize,
+                }))
+
+                # This test fails on Orthanc <= 1.5.8
+                self.assertEqual(0, CountAnswers({
+                    'Level' : level,
+                    'Query' : {
+                        'StudyInstanceUID' : '*'  # Wildcard matching not allowed for this VR
+                    },
+                    'Normalize' : normalize,
+                }))