def test_pending_cancel(self): """Test on_c_find yielding pending then cancel status""" # Note: success should be second, cancel should get ignored self.scp = DummyFindSCP() self.scp.statuses = [0xFF00, 0xFE00] self.scp.identifiers = [self.query, None] self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='G') status, identifier = next(result) assert status.Status == 0xFF00 assert identifier == self.query status, identifier = next(result) assert status.Status == 0x0000 assert identifier is None pytest.raises(StopIteration, next, result) assoc.release() self.scp.stop()
def test_multi_pending_failure(self): """Test on_c_find yielding multiple pending then failure status""" self.scp = DummyFindSCP() self.scp.statuses = [0xFF00, 0xFF01, 0xFF00, 0xA700, 0x0000] self.scp.identifiers = [self.query, self.query, self.query, None] self.scp.start() ae = AE() ae.add_requested_context( ProductCharacteristicsQueryInformationModelFind) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='PC') status, identifier = next(result) assert status.Status == 0xFF00 assert identifier == self.query status, identifier = next(result) assert status.Status == 0xFF01 assert identifier == self.query status, identifier = next(result) assert status.Status == 0xFF00 assert identifier == self.query status, identifier = next(result) assert status.Status == 0xA700 assert identifier is None pytest.raises(StopIteration, next, result) assoc.release() self.scp.stop()
def test_callback_status_dataset_multi(self): """Test on_c_find yielding a Dataset status with other elements""" self.scp = DummyFindSCP() self.scp.statuses = [Dataset()] self.scp.statuses[0].Status = 0xFF00 self.scp.statuses[0].ErrorComment = 'Test' self.scp.statuses[0].OffendingElement = 0x00010001 self.scp.identifiers = [self.query] self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='G') status, identifier = next(result) assert status.Status == 0xFF00 assert status.ErrorComment == 'Test' assert status.OffendingElement == 0x00010001 status, identifier = next(result) assert status.Status == 0x0000 assoc.release() self.scp.stop()
def test_scp_callback_info(self): """Test on_c_store caontext parameter""" self.scp = DummyFindSCP() self.scp.statuses = [Dataset(), 0x0000] self.scp.statuses[0].Status = 0xFF00 self.identifiers = [self.query, None] self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='G') status, identifier = next(result) assert status.Status == 0xFF00 status, identifier = next(result) assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert self.scp.info['requestor']['address'] == '127.0.0.1' assert self.scp.info['requestor']['ae_title'] == b'PYNETDICOM ' assert self.scp.info['requestor']['called_aet'] == b'ANY-SCP ' assert isinstance(self.scp.info['requestor']['port'], int) assert self.scp.info['acceptor']['port'] == 11112 assert self.scp.info['acceptor']['address'] == '127.0.0.1' assert self.scp.info['acceptor']['ae_title'] == b'PYNETDICOM ' assert self.scp.info['parameters']['message_id'] == 1 assert self.scp.info['parameters']['priority'] == 2 self.scp.stop()
def test_bad_req_identifier(self): """Test SCP handles a bad request identifier""" self.scp = DummyFindSCP() self.scp.statuses = [0xFF00] self.scp.identifiers = [self.query] self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery, ExplicitVRLittleEndian) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established req = C_FIND() req.MessageID = 1 req.AffectedSOPClassUID = GeneralRelevantPatientInformationQuery req.Priority = 2 req.Identifier = BytesIO( b'\x08\x00\x01\x00\x04\x00\x00\x00\x00\x08\x00\x49') assoc.dimse.send_msg(req, 1) rsp, _ = assoc.dimse.receive_msg(True) assert rsp.Status == 0xC310 assoc.release() self.scp.stop()
def test_scp_callback_info_move_origin(self): """Test on_c_store caontext parameter""" self.scp = DummyStorageSCP() self.scp.start() ae = AE() ae.add_requested_context(HangingProtocolStorage) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established status = assoc.send_c_store(DATASET, originator_aet=b'ORIGIN', originator_id=888) assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert self.scp.info['requestor']['address'] == '127.0.0.1' assert self.scp.info['requestor']['ae_title'] == b'PYNETDICOM ' assert self.scp.info['requestor']['called_aet'] == b'ANY-SCP ' assert isinstance(self.scp.info['requestor']['port'], int) assert self.scp.info['acceptor']['port'] == 11112 assert self.scp.info['acceptor']['address'] == '127.0.0.1' assert self.scp.info['acceptor']['ae_title'] == b'PYNETDICOM ' assert self.scp.info['parameters']['message_id'] == 1 assert self.scp.info['parameters']['priority'] == 2 assert self.scp.info['parameters']['originator_aet'] == b'ORIGIN ' assert self.scp.info['parameters']['originator_message_id'] == 888 self.scp.stop()
def test_scp_callback_context(self): """Test on_c_store caontext parameter""" self.scp = DummyFindSCP() self.scp.statuses = [Dataset(), 0x0000] self.scp.statuses[0].Status = 0xFF00 self.identifiers = [self.query, None] self.scp.start() ae = AE() ae.add_requested_context(GeneralRelevantPatientInformationQuery, '1.2.840.10008.1.2.1') ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established result = assoc.send_c_find(self.query, query_model='G') status, identifier = next(result) assert status.Status == 0xFF00 status, identifier = next(result) assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert self.scp.context.context_id == 1 assert self.scp.context.abstract_syntax == GeneralRelevantPatientInformationQuery assert self.scp.context.transfer_syntax == '1.2.840.10008.1.2.1' self.scp.stop()
def __init__(self, port=11112): self.ae = AE(port=port) self.ae.add_supported_context(PatientRootQueryRetrieveInformationModelGet) self.ae.add_supported_context(StudyRootQueryRetrieveInformationModelGet) self.ae.add_supported_context(PatientStudyOnlyQueryRetrieveInformationModelGet) self.ae.add_supported_context(CTImageStorage) self.ae.add_requested_context(CTImageStorage) DummyBaseSCP.__init__(self) self.statuses = [0x0000] ds = Dataset() ds.PatientName = 'Test' ds.SOPClassUID = CTImageStorage.UID ds.SOPInstanceUID = '1.2.3.4' self.datasets = [ds] self.no_suboperations = 1 self.cancel = False
def test_scp_callback_return_dataset_multi(self): """Test on_c_store returning a Dataset status with other elements""" self.scp = DummyStorageSCP() self.scp.status = Dataset() self.scp.status.Status = 0x0001 self.scp.status.ErrorComment = 'Test' self.scp.status.OffendingElement = 0x00080010 self.scp.start() ae = AE(scu_sop_class=[CTImageStorage]) assoc = ae.associate('localhost', 11112) assert assoc.is_established rsp = assoc.send_c_store(DATASET) assert rsp.Status == 0x0001 assert rsp.ErrorComment == 'Test' assert rsp.OffendingElement == 0x00080010 assoc.release() self.scp.stop()
def test_on_c_get_called(self): """ Check that SCP AE.on_c_get(dataset) was called """ self.scp = DummyGetSCP() self.scp.start() ds = Dataset() ds.PatientName = '*' ds.QueryRetrieveLevel = "PATIENT" ae = AE(scu_sop_class=[PatientRootQueryRetrieveInformationModelGet]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established for (status, ds) in assoc.send_c_get(ds, query_model='P'): assert status.Status == 0x0000 assoc.release() self.scp.stop()
def test_scp_callback_exception(self): """Test on_c_echo raising an exception""" self.scp = DummyVerificationSCP() def on_c_echo(context, info): raise ValueError self.scp.ae.on_c_echo = on_c_echo self.scp.start() ae = AE() ae.add_requested_context(VerificationSOPClass) assoc = ae.associate('localhost', 11112) assert assoc.is_established rsp = assoc.send_c_echo() assert rsp.Status == 0x0000 assoc.release() self.scp.stop()
def __init__(self, port=11112): self.ae = AE(scp_sop_class=[PatientRootQueryRetrieveInformationModelFind, StudyRootQueryRetrieveInformationModelFind, ModalityWorklistInformationFind, PatientStudyOnlyQueryRetrieveInformationModelFind], port=port) DummyBaseSCP.__init__(self) self.status = self.pending self.cancel = False
def test_on_c_store_called(self): """ Check that SCP AE.on_c_store(dataset) was called """ self.scp = DummyStorageSCP() self.scp.start() ae = AE(scu_sop_class=[RTImageStorage]) assoc = ae.associate('localhost', 11112) assert assoc.is_established status = assoc.send_c_store(DATASET) assert isinstance(status, Dataset) assert 'Status' in status assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert not assoc.is_established self.scp.stop()
def test_on_c_move_called(self): """ Check that SCP AE.on_c_move(dataset) was called """ self.scp = DummyMoveSCP() self.scp.start() ds = Dataset() ds.PatientName = '*' ds.QueryRetrieveLevel = "PATIENT" ae = AE(scu_sop_class=[PatientRootQueryRetrieveInformationModelMove]) assoc = ae.associate('localhost', 11112) self.assertTrue(assoc.is_established) for (status, ds) in assoc.send_c_move(ds, query_model='P', move_aet=b'TEST'): self.assertEqual(int(status), 0x0000) assoc.release() self.scp.stop()
def _setup_c_get_assoc(self): ae = AE(ae_title=self.client_ae_title, port=self.client_port) for context in QueryRetrievePresentationContexts: ae.add_requested_context(context.abstract_syntax) for context in StoragePresentationContexts: ae.add_requested_context(context.abstract_syntax) ae.on_c_store = self.on_c_store assoc = ae.associate(self.pacs_ip, self.pacs_port, ae_title=self.pacs_ae_title) return assoc
def test_scp_callback_return_dataset(self): """Test on_n_get returning a Dataset status""" self.scp = DummyGetSCP() self.scp.status = Dataset() # Unknown status self.scp.status.Status = 0x0001 self.scp.start() ae = AE() ae.add_requested_context(DisplaySystemSOPClass) assoc = ae.associate('localhost', 11112) assert assoc.is_established status, ds = assoc.send_n_get([(0x7fe0,0x0010)], DisplaySystemSOPClass, '1.2.840.10008.5.1.1.40.1') assert status.Status == 0x0001 assert ds.PatientName == 'Test' assoc.release() self.scp.stop()
def test_scp_callback_exception(self): """Test on_n_get raising an exception""" self.scp = DummyGetSCP() def on_n_get(attr, context, assoc_info): raise ValueError self.scp.ae.on_n_get = on_n_get self.scp.start() ae = AE() ae.add_requested_context(DisplaySystemSOPClass) assoc = ae.associate('localhost', 11112) assert assoc.is_established status, ds = assoc.send_n_get([(0x7fe0,0x0010)], DisplaySystemSOPClass, '1.2.840.10008.5.1.1.40.1') assert status.Status == 0x0110 assert ds is None assoc.release() self.scp.stop()
def __init__(self, port=11112): self.ae = AE(port=port) self.ae.add_supported_context( PatientRootQueryRetrieveInformationModelMove) self.ae.add_supported_context( StudyRootQueryRetrieveInformationModelMove) self.ae.add_supported_context( PatientStudyOnlyQueryRetrieveInformationModelMove) self.ae.add_supported_context(CTImageStorage, scp_role=True, scu_role=True) self.ae.add_supported_context(RTImageStorage) self.ae.add_supported_context( MRImageStorage, [ImplicitVRLittleEndian, JPEG2000Lossless]) self.ae.add_supported_context(HangingProtocolStorage) DummyBaseSCP.__init__(self) self.status = 0x0000 self.raise_exception = False
def __init__(self, port=11112): self.ae = AE(scp_sop_class=[PatientRootQueryRetrieveInformationModelGet, StudyRootQueryRetrieveInformationModelGet, PatientStudyOnlyQueryRetrieveInformationModelGet, CTImageStorage], scu_sop_class=[CTImageStorage], port=port) DummyBaseSCP.__init__(self) self.status = self.success self.cancel = False
def __init__(self, port=11112): self.ae = AE(port=port) self.ae.add_supported_context( PatientRootQueryRetrieveInformationModelMove) self.ae.add_supported_context( StudyRootQueryRetrieveInformationModelMove) self.ae.add_supported_context( PatientStudyOnlyQueryRetrieveInformationModelMove) self.ae.add_supported_context(CompositeInstanceRootRetrieveMove) self.ae.add_supported_context(HangingProtocolInformationModelMove) self.ae.add_supported_context( DefinedProcedureProtocolInformationModelMove) self.ae.add_supported_context(ColorPaletteInformationModelMove) self.ae.add_supported_context( GenericImplantTemplateInformationModelMove) self.ae.add_supported_context( ImplantAssemblyTemplateInformationModelMove) self.ae.add_supported_context(ImplantTemplateGroupInformationModelMove) self.ae.add_supported_context(RTImageStorage) self.ae.add_supported_context(CTImageStorage) self.ae.add_requested_context(RTImageStorage) self.ae.add_requested_context(CTImageStorage) DummyBaseSCP.__init__(self) self.statuses = [0x0000] self.store_status = 0x0000 ds = Dataset() ds.file_meta = Dataset() ds.file_meta.TransferSyntaxUID = ImplicitVRLittleEndian ds.PatientName = 'Test' ds.SOPClassUID = CTImageStorage ds.SOPInstanceUID = '1.2.3.4' self.datasets = [ds] self.no_suboperations = 1 self.destination_ae = ('localhost', 11112) self.cancel = False self.test_no_yield = False self.test_no_subops = False self.store_context = None self.store_info = None self.move_aet = None
def __init__(self, port=11112): self.ae = AE(scp_sop_class=[ PatientRootQueryRetrieveInformationModelMove, StudyRootQueryRetrieveInformationModelMove, PatientStudyOnlyQueryRetrieveInformationModelMove, CTImageStorage, RTImageStorage, MRImageStorage ], port=port) DummyBaseSCP.__init__(self) self.status = 0x0000 self.raise_exception = False
def test_scp_callback_context(self): """Test on_c_echo context parameter.""" self.scp = DummyVerificationSCP() self.scp.start() ae = AE(scu_sop_class=[VerificationSOPClass]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established rsp = assoc.send_c_echo() assert rsp.Status == 0x0000 assoc.release() assert assoc.is_released assert self.scp.context.context_id == 1 assert self.scp.context.abstract_syntax == '1.2.840.10008.1.1' assert self.scp.context.transfer_syntax == '1.2.840.10008.1.2.1' self.scp.stop()
def test_scp_callback_context(self): """Test on_c_store caontext parameter""" self.scp = DummyStorageSCP() self.scp.start() ae = AE(scu_sop_class=[CTImageStorage]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established status = assoc.send_c_store(DATASET) assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert self.scp.context.context_id == 1 assert self.scp.context.abstract_syntax == CTImageStorage.UID assert self.scp.context.transfer_syntax == '1.2.840.10008.1.2.1' self.scp.stop()
def test_on_c_echo_called(self): """ Check that SCP AE.on_c_echo() was called """ self.scp = DummyVerificationSCP() self.scp.start() ae = AE(scu_sop_class=[VerificationSOPClass]) ae.acse_timeout = 5 ae.dimse_timeout = 5 assoc = ae.associate('localhost', 11112) assert assoc.is_established status = assoc.send_c_echo() assert isinstance(status, Dataset) assert 'Status' in status assert status.Status == 0x0000 assoc.release() assert assoc.is_released assert not assoc.is_established self.scp.stop()
def test_associate_max_pdu(self): """ Check Association has correct max PDUs on either end """ self.scp = DummyVerificationSCP() self.scp.ae.maximum_pdu_size = 54321 self.scp.start() ae = AE(scu_sop_class=[VerificationSOPClass]) assoc = ae.associate('localhost', 11112, max_pdu=12345) self.assertTrue(self.scp.ae.active_associations[0].local_max_pdu == 54321) self.assertTrue(self.scp.ae.active_associations[0].peer_max_pdu == 12345) self.assertTrue(assoc.local_max_pdu == 12345) self.assertTrue(assoc.peer_max_pdu == 54321) assoc.release() # Check 0 max pdu value assoc = ae.associate('localhost', 11112, max_pdu=0) self.assertTrue(assoc.local_max_pdu == 0) self.assertTrue(self.scp.ae.active_associations[0].peer_max_pdu == 0) assoc.release() self.scp.stop()
def dcm_echo(ip, port): _ip = ip _port = port print('working') ae = AE(ae_title='DSTools', port=104) ae.add_requested_context(VerificationSOPClass) # Associate with the peer at IP address and Port assoc = ae.associate(_ip, _port) if assoc.is_established: string = 'success' assoc.release() print('success') else: var = 'ping ' + _ip if os.system(var) == 0: print('pinging') def isOpen(_ip, _port): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(3) try: s.connect((_ip, int(_port))) s.shutdown(socket.SHUT_RDWR) return True except: return False finally: s.close() if isOpen(_ip, _port): print('association') string = 'association' else: print('port') string = 'port' else: print('ping') string = 'ping' return string
def test_raise(self): """Test bad associate call""" ae = AE(scu_sop_class=[VerificationSOPClass]) with self.assertRaises(TypeError): ae.associate(1112, 11112) with self.assertRaises(TypeError): ae.associate('localhost', '1.2.3.4')
def __init__(self, dicom_home, port=11112, name="FINDSCP", prefer_uncompr=True, prefer_little=False, prefer_big=False, implicit=False, timeout=None, dimse_timeout=None, acse_timeout=60, pdu_max=16384, update_on_find=False, start=False): '''create a FindSCP (Service Class Provider) for query/retrieve and basic workflow management :param dicom_home: must be the base folder of dicom files **TODO: make this more robust :param port: TCP/IP port number to listen on :param name: the title/name for the ae. 'FINDSCP' is used if not defined. :param prefer_uncompr: prefer explicit VR local byte order (default) :param prefer_little: prefer explicit VR little endian TS :param perfer_big: prefer explicit VR big endian TS :param implicit: accept implicit VR little endian TS only :param timeout: timeout for connection requests (default None) :param acse_timeout: timeout for ACSE messages (default 60) :param dimse_timeout: timeout for the DIMSE messages (default None) :param pdu_max: set max receive pdu to n bytes (4096..131072) default 16382 :param update_on_find: if True, dicoms in dicom_home are updated on the find request ''' self.port = port # Base for dicom files (we can do better here) self.base = dicom_home self.dicoms = get_dicom_files(self.base) self.update_on_find = update_on_find # Update preferences self.update_transfer_syntax(prefer_uncompr=prefer_uncompr, prefer_little=prefer_little, prefer_big=prefer_big, implicit=implicit) ae = AE(scp_sop_class=QueryRetrieveSOPClassList, transfer_syntax=self.transfer_syntax, scu_sop_class=[], ae_title=name, port=self.port) # Set timeouts, name, transfer ae.maximum_pdu_size = pdu_max ae.network_timeout = timeout ae.acse_timeout = acse_timeout ae.dimse_timeout = dimse_timeout BaseSCP.__init__(self, ae=ae) self.status = self.pending_matches self.cancel = False if start is True: self.run()
class DummyGetSCP(DummyBaseSCP): """A threaded dummy get SCP used for testing""" def __init__(self, port=11112): self.ae = AE(port=port) self.ae.add_supported_context(PatientRootQueryRetrieveInformationModelGet) self.ae.add_supported_context(StudyRootQueryRetrieveInformationModelGet) self.ae.add_supported_context(PatientStudyOnlyQueryRetrieveInformationModelGet) self.ae.add_supported_context(CTImageStorage) self.ae.add_requested_context(CTImageStorage) DummyBaseSCP.__init__(self) self.statuses = [0x0000] ds = Dataset() ds.PatientName = 'Test' ds.SOPClassUID = CTImageStorage.UID ds.SOPInstanceUID = '1.2.3.4' self.datasets = [ds] self.no_suboperations = 1 self.cancel = False def on_c_get(self, ds, context, info): """Callback for ae.on_c_get""" self.context = context self.info = info time.sleep(self.delay) ds = Dataset() ds.PatientName = '*' ds.QueryRetrieveLevel = "PATIENT" yield self.no_suboperations for (status, ds) in zip(self.statuses, self.datasets): if self.cancel: yield 0xFE00, None return yield status, ds def on_c_cancel_get(self): """Callback for ae.on_c_cancel_get""" self.cancel = True
def test_ae_aborts_assoc(self): """ Association aborts OK """ self.scp = DummyVerificationSCP() self.scp.start() ae = AE(scu_sop_class=[VerificationSOPClass]) ae.acse_timeout = 5 # Test N associate/abort cycles for ii in range(5): assoc = ae.associate('localhost', 11112) self.assertTrue(assoc.is_established) if assoc.is_established: assoc.abort() self.assertFalse(assoc.is_established) self.assertTrue(assoc.is_aborted) self.assertFalse(assoc.is_released) self.assertFalse(assoc.is_rejected) #self.assertTrue(ae.active_associations == []) self.scp.stop()