def test_one_req_one_acc_accept_trans_diff(self): """Test negotiation one req/acc, matching accepted, multi trans.""" context_a = PresentationContext() context_a.context_id = 1 context_a.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_a.transfer_syntax = [ '1.2.840.10008.1.2', '1.2.840.10008.1.2.1', '1.2.840.10008.1.2.2' ] context_b = PresentationContext() context_b.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_b.transfer_syntax = ['1.2.840.10008.1.2.2'] rq_contexts = [context_a] acc_contexts = self.test_acc(rq_contexts, [context_b]) for context in acc_contexts: context._abstract_syntax = None result = self.test_func(rq_contexts, acc_contexts) assert len(result) == 1 context = result[0] assert context.context_id == 1 assert context.abstract_syntax == '1.2.840.10008.5.1.4.1.1.2' assert context.result == 0x00 assert context.transfer_syntax == ['1.2.840.10008.1.2.2']
def test_dupe_abs_req_no_acc(self): """Test negotiation with duplicate requestor, no acceptor contexts.""" context_a = PresentationContext() context_a.context_id = 1 context_a.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_a.transfer_syntax = ['1.2.840.10008.1.2'] context_b = PresentationContext() context_b.context_id = 3 context_b.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_b.transfer_syntax = ['1.2.840.10008.1.2.1'] context_c = PresentationContext() context_c.context_id = 5 context_c.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_c.transfer_syntax = ['1.2.840.10008.1.2.2'] rq_contexts = [context_a, context_b, context_c] acc_contexts = self.test_acc(rq_contexts, []) for context in acc_contexts: context._abstract_syntax = None result = self.test_func(rq_contexts, acc_contexts) assert len(result) == 3 for context in result: assert context.context_id in [1, 3, 5] assert context.abstract_syntax == '1.2.840.10008.5.1.4.1.1.2' assert context.result == 0x03
def test_dupe_abs_req(self): """Test negotiation with duplicate requestor, no acceptor contexts.""" context_a = PresentationContext() context_a.context_id = 1 context_a.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_a.transfer_syntax = ['1.2.840.10008.1.2'] context_b = PresentationContext() context_b.context_id = 3 context_b.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_b.transfer_syntax = ['1.2.840.10008.1.2.1'] context_c = PresentationContext() context_c.context_id = 5 context_c.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_c.transfer_syntax = ['1.2.840.10008.1.2.2'] t_syntax = [ '1.2.840.10008.1.2', '1.2.840.10008.1.2.1', '1.2.840.10008.1.2.2' ] context_d = PresentationContext() context_d.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_d.transfer_syntax = t_syntax context_list = [context_a, context_b, context_c] result = self.test_func(context_list, [context_d]) assert len(result) == 3 for ii, context in enumerate(result): assert context.context_id in [1, 3, 5] assert context.abstract_syntax == '1.2.840.10008.5.1.4.1.1.2' assert context.result == 0x00 assert context.transfer_syntax == [t_syntax[ii]]
def test_private_transfer_syntax(self): """Test negotiation with private transfer syntax""" context_a = PresentationContext() context_a.context_id = 1 context_a.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_a.transfer_syntax = ['1.2.3.4'] context_b = PresentationContext() context_b.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_b.transfer_syntax = ['1.2.840.10008.1.2.1', '1.2.3.4'] result = self.test_func([context_a], [context_b]) assert len(result) == 1 context = result[0] assert context.context_id == 1 assert context.abstract_syntax == '1.2.840.10008.5.1.4.1.1.2' assert context.result == 0x00 assert context.transfer_syntax == ['1.2.3.4']
def test_no_req_one_acc_raise(self): """Test negotiation with no requestor, one acceptor contexts.""" context = PresentationContext() context.context_id = 1 context.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context.transfer_syntax = ['1.2.840.10008.1.2'] with pytest.raises(ValueError): result = self.test_func([], [context])
def test_one_req_one_acc_mismatch(self): """Test negotiation one req/acc, mismatched rejected""" context_a = PresentationContext() context_a.context_id = 1 context_a.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context_a.transfer_syntax = [ '1.2.840.10008.1.2', '1.2.840.10008.1.2.1' ] context_b = PresentationContext() context_b.abstract_syntax = '1.2.840.10008.5.1.4.1.1.4' context_b.transfer_syntax = ['1.2.840.10008.1.2.2'] result = self.test_func([context_a], [context_b]) assert len(result) == 1 context = result[0] assert context.context_id == 1 assert context.abstract_syntax == '1.2.840.10008.5.1.4.1.1.2' assert context.result == 0x03
def test_no_req_one_acc(self): """Test negotiation with no requestor, one acceptor contexts.""" context = PresentationContext() context.context_id = 1 context.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context.transfer_syntax = ['1.2.840.10008.1.2'] result = self.test_func([], [context]) assert result == []
def test_add_private_transfer_syntax(self): """Test adding private transfer syntaxes""" pc = PresentationContext() pc.context_id = 1 pc.add_transfer_syntax('2.16.840.1.113709.1.2.2') assert '2.16.840.1.113709.1.2.2' in pc._transfer_syntax pc.transfer_syntax = ['2.16.840.1.113709.1.2.1'] assert '2.16.840.1.113709.1.2.1' in pc._transfer_syntax
def test_transfer_syntax_nonconformant(self, caplog): """Test setting non-conformant transfer syntaxes""" caplog.set_level(logging.DEBUG, logger='pynetdicom3.presentation') pc = PresentationContext() pc.context_id = 1 pc.transfer_syntax = ['1.4.1.', '1.2.840.10008.1.2'] assert pc.transfer_syntax == ['1.4.1.', '1.2.840.10008.1.2'] assert ("A non-conformant UID has been added to 'transfer_syntax'" in caplog.text)
def test_typical(self): """Test a typical set of presentation context negotiations.""" req_contexts = [] for ii, context in enumerate(StoragePresentationContexts): pc = PresentationContext() pc.context_id = ii * 2 + 1 pc.abstract_syntax = context.abstract_syntax pc.transfer_syntax = [ '1.2.840.10008.1.2', '1.2.840.10008.1.2.1', '1.2.840.10008.1.2.2' ] req_contexts.append(pc) acc_contexts = [] for uid in UID_dictionary: pc = PresentationContext() pc.abstract_syntax = uid pc.transfer_syntax = [ '1.2.840.10008.1.2', '1.2.840.10008.1.2.1', '1.2.840.10008.1.2.2' ] acc_contexts.append(pc) acc_contexts = self.test_acc(req_contexts, acc_contexts) for context in acc_contexts: context._abstract_syntax = None results = self.test_func(req_contexts, acc_contexts) assert len(results) == len(req_contexts) for ii, context in enumerate(req_contexts): assert results[ii].context_id == context.context_id assert results[ii].abstract_syntax == context.abstract_syntax if results[ ii].abstract_syntax == '1.2.840.10008.5.1.4.1.1.1.1.1.1': assert results[ii].result == 0x03 elif results[ ii].abstract_syntax == '1.2.840.10008.5.1.1.4.1.1.3.1': assert results[ii].result == 0x03 else: assert results[ii].result == 0x00 assert results[ii].transfer_syntax == ['1.2.840.10008.1.2']
def test_tuple(self): """Test the .as_tuple""" context = PresentationContext() context.context_id = 3 context.abstract_syntax = '1.2.840.10008.1.1' context.transfer_syntax = ['1.2.840.10008.1.2'] out = context.as_tuple assert out.context_id == 3 assert out.abstract_syntax == '1.2.840.10008.1.1' assert out.transfer_syntax == '1.2.840.10008.1.2'
def test_transfer_syntax(self): """Test transfer syntax setter""" pc = PresentationContext() pc.context_id = 1 pc.transfer_syntax = ['1.2.840.10008.1.2'] assert pc.transfer_syntax[0] == UID('1.2.840.10008.1.2') assert isinstance(pc.transfer_syntax[0], UID) pc.transfer_syntax = [b'1.2.840.10008.1.2.1'] assert pc.transfer_syntax[0] == UID('1.2.840.10008.1.2.1') assert isinstance(pc.transfer_syntax[0], UID) pc.transfer_syntax = [UID('1.2.840.10008.1.2.2')] assert pc.transfer_syntax[0] == UID('1.2.840.10008.1.2.2') assert isinstance(pc.transfer_syntax[0], UID) with pytest.raises(TypeError): pc.transfer_syntax = UID('1.4.1') pc.transfer_syntax = [1234, UID('1.4.1')] assert pc.transfer_syntax == [UID('1.4.1')]
def test_string_output(self): """Test string output""" pc = PresentationContext() pc.context_id = 1 pc.abstract_syntax = '1.1.1' pc.transfer_syntax = ['1.2.840.10008.1.2', '1.2.3'] pc._scp_role = True pc._scu_role = False pc.result = 0x02 assert '1.1.1' in pc.__str__() assert 'Implicit' in pc.__str__() assert 'Provider Rejected' in pc.__str__()
def test_one_req_one_acc_match(self): """Test negotiation one req/acc, matching accepted.""" context = PresentationContext() context.context_id = 1 context.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context.transfer_syntax = ['1.2.840.10008.1.2'] result = self.test_func([context], [context]) assert len(result) == 1 context = result[0] assert context.context_id == 1 assert context.abstract_syntax == '1.2.840.10008.5.1.4.1.1.2' assert context.result == 0x00 assert context.transfer_syntax == ['1.2.840.10008.1.2']
def test_setter(self, good_init): """Test the presentation context class init""" (context_id, abs_syn, tran_syn) = good_init pc = PresentationContext() pc.context_id = context_id pc.abstract_syntax = abs_syn pc.transfer_syntax = tran_syn assert pc.context_id == context_id assert pc.abstract_syntax == abs_syn assert pc.transfer_syntax == tran_syn assert pc._scu_role is None assert pc._scp_role is None assert pc.result is None
def test_equality(self): """Test presentation context equality""" pc_a = PresentationContext() pc_a.context_id = 1 pc_a.abstract_syntax = '1.1.1' pc_a.transfer_syntax = ['1.2.840.10008.1.2'] pc_b = PresentationContext() pc_b.context_id = 1 pc_b.abstract_syntax = '1.1.1' pc_b.transfer_syntax = ['1.2.840.10008.1.2'] assert pc_a == pc_a assert pc_a == pc_b assert not pc_a != pc_b assert not pc_a != pc_a pc_a._scp_role = True assert not pc_a == pc_b pc_b._scp_role = True assert pc_a == pc_b pc_a._scu_role = True assert not pc_a == pc_b pc_b._scu_role = True assert pc_a == pc_b assert not 'a' == pc_b
def test_private_abstract_syntax(self): """Test negotiation with private abstract syntax""" context_a = PresentationContext() context_a.context_id = 1 context_a.abstract_syntax = '1.2.3.4' context_a.transfer_syntax = ['1.2.840.10008.1.2.1'] context_b = PresentationContext() context_b.abstract_syntax = '1.2.3.4' context_b.transfer_syntax = ['1.2.840.10008.1.2.1'] rq_contexts = [context_a] acc_contexts = self.test_acc(rq_contexts, [context_b]) for context in acc_contexts: context._abstract_syntax = None result = self.test_func(rq_contexts, acc_contexts) assert len(result) == 1 context = result[0] assert context.context_id == 1 assert context.abstract_syntax == '1.2.3.4' assert context.result == 0x00 assert context.transfer_syntax == ['1.2.840.10008.1.2.1']
def test_one_req_no_acc(self): """Test negotiation with one requestor, no acceptor contexts.""" context = PresentationContext() context.context_id = 1 context.abstract_syntax = '1.2.840.10008.5.1.4.1.1.2' context.transfer_syntax = ['1.2.840.10008.1.2'] result = self.test_func([context], []) assert len(result) == 1 context = result[0] assert context.context_id == 1 assert context.abstract_syntax == '1.2.840.10008.5.1.4.1.1.2' assert context.transfer_syntax[0] == '1.2.840.10008.1.2' assert len(context.transfer_syntax) == 1 assert context.result == 0x02
def test_conversion(self): """ Check conversion to a PDU produces the correct output """ assoc = A_ASSOCIATE() assoc.application_context_name = "1.2.840.10008.3.1.1.1" assoc.calling_ae_title = 'ECHOSCU' assoc.called_ae_title = 'ANY-SCP' assoc.maximum_length_received = 16382 assoc.implementation_class_uid = '1.2.826.0.1.3680043.9.3811.0.9.0' imp_ver_name = ImplementationVersionNameNotification() imp_ver_name.implementation_version_name = 'PYNETDICOM_090' assoc.user_information.append(imp_ver_name) pc = PresentationContext() pc.context_id = 1 pc.abstract_syntax = '1.2.840.10008.1.1' pc.transfer_syntax = ['1.2.840.10008.1.2'] assoc.presentation_context_definition_list = [pc] pdu = A_ASSOCIATE_RQ() pdu.from_primitive(assoc) data = pdu.encode() ref = b"\x01\x00\x00\x00\x00\xd1\x00\x01\x00\x00\x41\x4e\x59\x2d\x53\x43" \ b"\x50\x20\x20\x20\x20\x20\x20\x20\x20\x20\x45\x43\x48\x4f\x53\x43" \ b"\x55\x20\x20\x20\x20\x20\x20\x20\x20\x20\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x15\x31\x2e" \ b"\x32\x2e\x38\x34\x30\x2e\x31\x30\x30\x30\x38\x2e\x33\x2e\x31\x2e" \ b"\x31\x2e\x31\x20\x00\x00\x2e\x01\x00\x00\x00\x30\x00\x00\x11\x31" \ b"\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30\x30\x30\x38\x2e\x31\x2e\x31" \ b"\x40\x00\x00\x11\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30\x30\x30" \ b"\x38\x2e\x31\x2e\x32\x50\x00\x00\x3e\x51\x00\x00\x04\x00\x00\x3f" \ b"\xfe\x52\x00\x00\x20\x31\x2e\x32\x2e\x38\x32\x36\x2e\x30\x2e\x31" \ b"\x2e\x33\x36\x38\x30\x30\x34\x33\x2e\x39\x2e\x33\x38\x31\x31\x2e" \ b"\x30\x2e\x39\x2e\x30\x55\x00\x00\x0e\x50\x59\x4e\x45\x54\x44\x49" \ b"\x43\x4f\x4d\x5f\x30\x39\x30" assert data == ref
def test_transfer_syntax_duplicate(self): """Test the transfer_syntax setter with duplicate UIDs.""" pc = PresentationContext() pc.transfer_syntax = ['1.3', '1.3'] assert pc.transfer_syntax == ['1.3']
def acceptor_contexts(self, contexts): """Set the Acceptor's presentation contexts. Must be a list of pynetdicom3.utils.PresentationContext There are two possible situations 1. The local AE issues the request and receives the response 2. The peer AE issues the request and the local must determine the response The first situation means that the acceptor has already decided on a Result and (if accepted) which Transfer Syntax to use The second situation means that we must determine whether to accept or reject presentation context and which Transfer Syntax to use requestor_contexts cannot be an empty list When the local AE is making the request, this is just the contents of the A-ASSOCIATE PresentationContextDefinitionResultList parameter (Result value will not be None) When the peer AE is making the request this will be the list of the SCP supported SOP classes combined with the supported Transfer Syntax(es) (Result value will be None) FIXME: This needs to be refactored, its slow and overly complex FIXME: It would be better to have a separate method to call when the user wants the contexts evaluated """ if self.requestor_contexts == []: raise RuntimeError("You can only set the Acceptor's presentation " "contexts after the Requestor's") if not isinstance(contexts, list): raise TypeError("acceptor_contexts must be a list of " "PresentationContext items") # Validate the supplied contexts self._acceptor_contexts = [] for ii in contexts: if isinstance(ii, PresentationContext): self._acceptor_contexts.append(ii) else: raise TypeError("acceptor_contexts must be a list of " "PresentationContext items") # Generate accepted_contexts and rejected_contexts self.accepted = [] self.rejected = [] if self._acceptor_contexts != [] and self._requestor_contexts != []: # For each of the contexts available to the acceptor for ii_req in self._requestor_contexts: # Get the acceptor context with the same Abstract Syntax as # the requestor context acc_context = None for ii_acc in self._acceptor_contexts: # The acceptor context will only have an abstract syntax # if we are the Acceptor, otherwise we have to match # using the IDs # If we are the Requestor then the Acceptor contexts # will have no Abstract Syntax if ii_acc.abstract_syntax is not None: if ii_acc.abstract_syntax == ii_req.abstract_syntax: acc_context = ii_acc else: if ii_acc.context_id == ii_req.context_id: acc_context = ii_acc # Set Abstract Syntax (for convenience) ii_acc.abstract_syntax = ii_req.abstract_syntax # Create a new PresentationContext item that will store the # results from the negotiation result = PresentationContext() result.context_id = ii_req.context_id result.abstract_syntax = ii_req.abstract_syntax # If no matching Abstract Syntax then we are the Acceptor and # we reject the current context (0x03 - abstract syntax not # supported) if acc_context is None: # FIXME: make pdu not require this. result.transfer_syntax = [ii_req.transfer_syntax[0]] result.result = 0x03 result = self.negotiate_scp_scu_role(ii_req, result) self.rejected.append(result) # If there is a matching Abstract Syntax then check to see if # the result is None (indicates we are the Acceptor) or # has a value set (indicates we are the Requestor) else: # We are the Acceptor and must decide to accept or reject # the context if acc_context.result is None: # Check the Transfer Syntaxes # We accept the first matching transfer syntax for transfer_syntax in acc_context.transfer_syntax: # The local transfer syntax is used in order to # enforce preference based on position if transfer_syntax in ii_req.transfer_syntax: result.transfer_syntax = [transfer_syntax] result.result = 0x00 result = self.negotiate_scp_scu_role( ii_req, result) self.accepted.append(result) break # Refuse sop class because TS not supported else: # FIXME: make pdu not require this. result.transfer_syntax = [transfer_syntax] result.result = 0x04 result = self.negotiate_scp_scu_role( ii_req, result) self.rejected.append(result) # We are the Requestor and the Acceptor has accepted this # context elif acc_context.result == 0x00: # The accepted transfer syntax (there is only 1) result.transfer_syntax = [ acc_context.transfer_syntax[0] ] # Add it to the list of accepted presentation contexts self.accepted.append(result) # We are the Requestor and the Acceptor has rejected this # context elif acc_context.result in [0x01, 0x02, 0x03, 0x04]: # The rejected transfer syntax(es) result.transfer_syntax = acc_context.transfer_syntax # Add it to the list of accepted presentation contexts self.rejected.append(result) else: raise ValueError( "Invalid 'Result' parameter in the " "Acceptor's Presentation Context list")