def test_unicode_chars_in_exception(self): class SomeService(Service): @srpc(Unicode(pattern=u'x'), _returns=Unicode) def some_call(s): test(should, never, reach, here) app = Application([SomeService], "tns", name="test_mandatory_elements", in_protocol=XmlDocument(validator='lxml'), out_protocol=XmlDocument()) server = WsgiApplication(app) req = ( u'<some_call xmlns="tns">' u'<s>Ğ</s>' u'</some_call>' ).encode('utf8') print("AAA") resp = server({ 'QUERY_STRING': '', 'PATH_INFO': '/', 'REQUEST_METHOD': 'POST', 'SERVER_NAME': 'localhost', 'SERVER_PORT': '80', 'wsgi.input': BytesIO(req), "wsgi.url_scheme": 'http', }, lambda x, y: print(x,y)) print("AAA") assert u'Ğ'.encode('utf8') in b''.join(resp)
def test_soap_bare_wrapped_array_output(self): class SomeService(Service): @rpc(_body_style='bare', _returns=Array(String)) def some_call(ctx): return ['abc', 'def'] app = Application([SomeService], 'tns', in_protocol=Soap11(), out_protocol=Soap11(cleanup_namespaces=True)) req = b""" <soap11env:Envelope xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="tns"> <soap11env:Body> <tns:some_call/> </soap11env:Body> </soap11env:Envelope> """ server = WsgiApplication(app) resp = etree.fromstring(b''.join(server({ 'QUERY_STRING': '', 'PATH_INFO': '/call', 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': 'text/xml; charset=utf8', 'wsgi.input': BytesIO(req) }, start_response, "http://null"))) print(etree.tostring(resp, pretty_print=True)) assert resp[0].tag == '{http://schemas.xmlsoap.org/soap/envelope/}Body' assert resp[0][0].tag == '{tns}some_call' + RESPONSE_SUFFIX assert resp[0][0][0].text == 'abc' assert resp[0][0][1].text == 'def'
def get_object_as_xml_cloth(inst, cls=None, no_namespace=False, encoding='utf8'): """Returns an ElementTree representation of a :class:`spyne.model.complex.ComplexModel` subclass. :param inst: The instance of the class to be serialized. :param cls: The class to be serialized. Optional. :param root_tag_name: The root tag string to use. Defaults to the output of ``value.__class__.get_type_name_ns()``. :param no_namespace: When true, namespace information is discarded. """ if cls is None: cls = inst.__class__ if cls.get_namespace() is None and no_namespace is None: no_namespace = True if no_namespace is None: no_namespace = False ostr = BytesIO() xml_cloth = XmlCloth(use_ns=(not no_namespace)) ctx = FakeContext() with etree.xmlfile(ostr, encoding=encoding) as xf: ctx.outprot_ctx.doctype_written = False ctx.protocol.prot_stack = tlist([], ProtocolMixin) tn = cls.get_type_name() ret = xml_cloth.subserialize(ctx, cls, inst, xf, tn) assert not isgenerator(ret) return ostr.getvalue()
def test_one(self): class SomeComplexModel(ComplexModel): s = Unicode i = Integer v = SomeComplexModel(s='a', i=1), class SomeService(ServiceBase): @rpc(_returns=SomeComplexModel) def get(ctx): return v desc = SomeService.public_methods['get'] ctx = FakeContext(out_object=v, descriptor=desc) ostr = ctx.out_stream = BytesIO() XmlDocument(Application([SomeService], __name__)) \ .serialize(ctx, XmlDocument.RESPONSE) elt = etree.fromstring(ostr.getvalue()) print(etree.tostring(elt, pretty_print=True)) assert elt.xpath('x:getResult/x:i/text()', namespaces={'x': __name__}) == ['1'] assert elt.xpath('x:getResult/x:s/text()', namespaces={'x': __name__}) == ['a']
def test_many(self): class SomeComplexModel(ComplexModel): s = Unicode i = Integer v = [ SomeComplexModel(s='a', i=1), SomeComplexModel(s='b', i=2), SomeComplexModel(s='c', i=3), SomeComplexModel(s='d', i=4), SomeComplexModel(s='e', i=5), ] class SomeService(Service): @rpc(_returns=Array(SomeComplexModel)) def get(ctx): return v desc = SomeService.public_methods['get'] ctx = FakeContext(out_object=[v], descriptor=desc) ostr = ctx.out_stream = BytesIO() XmlDocument(Application([SomeService], __name__)) \ .serialize(ctx, XmlDocument.RESPONSE) elt = etree.fromstring(ostr.getvalue()) print(etree.tostring(elt, pretty_print=True)) assert elt.xpath('x:getResult/x:SomeComplexModel/x:i/text()', namespaces={'x': __name__}) == ['1', '2', '3', '4', '5'] assert elt.xpath('x:getResult/x:SomeComplexModel/x:s/text()', namespaces={'x': __name__}) == ['a', 'b', 'c', 'd', 'e']
def test_thread_aux_wsgi(self): import logging logging.basicConfig(level=logging.DEBUG) data = set() class SomeService(Service): @srpc(String, _returns=String) def call(s): data.add(s) class AuxService(Service): __aux__ = ThreadAuxProc() @srpc(String, _returns=String) def call(s): data.add(s + "aux") app = Application([SomeService, AuxService], 'tns', in_protocol=HttpRpc(), out_protocol=HttpRpc()) server = WsgiApplication(app) server({ 'QUERY_STRING': 's=hey', 'PATH_INFO': '/call', 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': 'text/xml; charset=utf8', 'SERVER_NAME': 'localhost', 'wsgi.input': BytesIO(), }, start_response, "http://null") import time time.sleep(1) assert data == set(['hey', 'heyaux'])
def subunit2junitxml(ctr): from testtools import ExtendedToStreamDecorator from testtools import StreamToExtendedDecorator from subunit import StreamResultToBytes from subunit.filters import filter_by_result from subunit.filters import run_tests_from_stream from spyne.util.six import BytesIO from junitxml import JUnitXmlResult sys.argv = ['subunit-1to2'] subunit1_file_name = 'test_result.%d.subunit' % ctr subunit2 = BytesIO() run_tests_from_stream(open(subunit1_file_name, 'rb'), ExtendedToStreamDecorator( StreamResultToBytes(subunit2))) subunit2.seek(0) sys.argv = ['subunit2junitxml'] sys.stdin = subunit2 def f(output): return StreamToExtendedDecorator(JUnitXmlResult(output)) junit_file_name = 'test_result.%d.xml' % ctr filter_by_result(f, junit_file_name, True, False, protocol_version=2, passthrough_subunit=True, input_stream=subunit2)
def serialize(self, ctx, message): """Uses ``ctx.out_object``, ``ctx.out_header`` or ``ctx.out_error`` to set ``ctx.out_body_doc``, ``ctx.out_header_doc`` and ``ctx.out_document`` as an ``lxml.etree._Element instance``. Not meant to be overridden. """ assert message in (self.REQUEST, self.RESPONSE) self.event_manager.fire_event('before_serialize', ctx) if ctx.out_stream is None: ctx.out_stream = BytesIO() logger.debug("%r %d", ctx.out_stream, id(ctx.out_stream)) if ctx.out_error is not None: # All errors at this point must be Fault subclasses. inst = ctx.out_error cls = inst.__class__ name = cls.get_type_name() if self.developer_mode: # FIXME: the eff is this? ctx.out_object = (inst, ) retval = self._incgen(ctx, cls, inst, name) else: with self.docfile(ctx.out_stream, encoding=self.encoding) as xf: retval = self.to_parent(ctx, cls, inst, xf, name) else: assert message is self.RESPONSE result_class = ctx.descriptor.out_message name = result_class.get_type_name() if ctx.descriptor.body_style == BODY_STYLE_WRAPPED: if self.ignore_wrappers: result_inst = ctx.out_object[0] while result_class.Attributes._wrapper and \ len(result_class._type_info) == 1: result_class, = \ result_class._type_info.values() else: result_inst = result_class() for i, attr_name in enumerate( result_class._type_info.keys()): setattr(result_inst, attr_name, ctx.out_object[i]) else: result_inst, = ctx.out_object retval = self._incgen(ctx, result_class, result_inst, name) self.event_manager.fire_event('after_serialize', ctx) return retval
def test_simple_aux_wsgi(self): data = [] class Service(ServiceBase): @srpc(String, _returns=String) def call(s): data.append(s) class AuxService(ServiceBase): __aux__ = SyncAuxProc() @srpc(String, _returns=String) def call(s): data.append(s) app = Application([Service, AuxService], 'tns', in_protocol=HttpRpc(), out_protocol=HttpRpc()) server = WsgiApplication(app) server( { 'QUERY_STRING': 's=hey', 'PATH_INFO': '/call', 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': 'text/xml', 'SERVER_NAME': 'localhost', 'wsgi.input': BytesIO(), }, start_response, "http://null") assert data == ['hey', 'hey']
def test_soap_bare_empty_output(self): class SomeService(ServiceBase): @rpc(String, _body_style='bare') def some_call(ctx, s): assert s == 'abc' app = Application([SomeService], 'tns', in_protocol=Soap11(), out_protocol=Soap11(cleanup_namespaces=True)) req = b""" <soap11env:Envelope xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="tns"> <soap11env:Body> <tns:some_call>abc</tns:some_call> </soap11env:Body> </soap11env:Envelope> """ server = WsgiApplication(app) resp = etree.fromstring(b''.join(server({ 'QUERY_STRING': '', 'PATH_INFO': '/call', 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': 'text/xml; charset=utf8', 'SERVER_NAME': 'localhost', 'wsgi.input': BytesIO(req), }, start_response, "http://null"))) print(etree.tostring(resp, pretty_print=True)) assert resp[0].tag == '{http://schemas.xmlsoap.org/soap/envelope/}Body' assert len(resp[0]) == 1 assert resp[0][0].tag == '{tns}some_call'+ RESPONSE_SUFFIX assert len(resp[0][0]) == 0
def test_file(self): v = b'aaaa' f = BytesIO(v) elt = get_object_as_xml(File.Value(handle=f), File, 'B') eltstr = etree.tostring(elt) print(eltstr) assert elt.text == b64encode(v).decode('ascii')
def serialize(self, ctx, message): """Uses ``ctx.out_object``, ``ctx.out_header`` or ``ctx.out_error`` to set ``ctx.out_body_doc``, ``ctx.out_header_doc`` and ``ctx.out_document`` as an ``lxml.etree._Element instance``. Not meant to be overridden. """ assert message in (self.REQUEST, self.RESPONSE) self.event_manager.fire_event('before_serialize', ctx) if ctx.out_stream is None: ctx.out_stream = BytesIO() logger.debug("%r %d", ctx.out_stream, id(ctx.out_stream)) if ctx.out_error is not None: # All errors at this point must be Fault subclasses. inst = ctx.out_error cls = inst.__class__ name = cls.get_type_name() ctx.out_document = E.div() with self.docfile(ctx.out_stream) as xf: # as XmlDocument is not push-ready yet, this is what we do. # this is an ugly hack, bear with me. retval = XmlCloth.HtmlMicroFormat() \ .to_parent(ctx, cls, inst, xf, name) else: assert message is self.RESPONSE result_message_class = ctx.descriptor.out_message name = result_message_class.get_type_name() if ctx.descriptor.body_style == BODY_STYLE_WRAPPED: if self.ignore_wrappers: result_message = ctx.out_object[0] while result_message_class.Attributes._wrapper and \ len(result_message_class._type_info) == 1: result_message_class, = \ result_message_class._type_info.values() else: result_message = result_message_class() for i, attr_name in enumerate( result_message_class._type_info.keys()): setattr(result_message, attr_name, ctx.out_object[i]) else: result_message, = ctx.out_object retval = self.incgen(ctx, result_message_class, result_message, name) self.event_manager.fire_event('after_serialize', ctx) return retval
def test_fault_generation(self): class SoapException(ServiceBase): @srpc() def soap_exception(): raise Fault("Client.Plausible", "A plausible fault", 'http://faultactor.example.com') app = Application([SoapException], 'tns', in_protocol=Soap12(), out_protocol=Soap12()) req = b""" <soap12env:Envelope xmlns:soap12env="http://www.w3.org/2003/05/soap-envelope" xmlns:tns="tns"> <soap12env:Body> <tns:soap_exception/> </soap12env:Body> </soap12env:Envelope> """ server = WsgiApplication(app) response = etree.fromstring(b''.join( server( { 'QUERY_STRING': '', 'PATH_INFO': '/call', 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': 'text/xml; charset=utf8', 'wsgi.input': BytesIO(req) }, start_response, "http://null"))) response_str = etree.tostring(response, pretty_print=True) print(response_str) expected = b""" <soap12env:Envelope xmlns:soap12env="http://www.w3.org/2003/05/soap-envelope"> <soap12env:Body> <soap12env:Fault> <soap12env:Reason> <soap12env:Text xml:lang="en">A plausible fault</soap12env:Text> </soap12env:Reason> <soap12env:Role>http://faultactor.example.com</soap12env:Role> <soap12env:Code> <soap12env:Value>soap12env:Sender</soap12env:Value> <soap12env:Subcode> <soap12env:Value>Plausible</soap12env:Value> </soap12env:Subcode> </soap12env:Code> </soap12env:Fault> </soap12env:Body> </soap12env:Envelope>""" if not LXMLOutputChecker().check_output(expected, response_str, PARSE_XML): raise Exception("Got: %s but expected: %s" % (response_str, expected))
def test_rpc(self): data = {"a":"b", "c": "d"} class KeyValuePair(ComplexModel): key = Unicode value = Unicode class SomeService(Service): @rpc(String(max_occurs='unbounded'), _returns=Array(KeyValuePair), _in_variable_names={ 'keys': 'key' } ) def get_values(ctx, keys): for k in keys: yield KeyValuePair(key=k, value=data[k]) application = Application([SomeService], in_protocol=MessagePackRpc(), out_protocol=MessagePackRpc(ignore_wrappers=False), name='Service', tns='tns') server = WsgiApplication(application) input_string = msgpack.packb([0, 0, "get_values", [["a", "c"]]]) input_stream = BytesIO(input_string) ret = server({ 'CONTENT_LENGTH': str(len(input_string)), 'CONTENT_TYPE': 'application/x-msgpack', 'HTTP_CONNECTION': 'close', 'HTTP_CONTENT_LENGTH': str(len(input_string)), 'HTTP_CONTENT_TYPE': 'application/x-msgpack', 'PATH_INFO': '/', 'QUERY_STRING': '', 'SERVER_NAME': 'localhost', 'SERVER_PORT': '7000', 'REQUEST_METHOD': 'POST', 'wsgi.url_scheme': 'http', 'wsgi.input': input_stream, }, start_response) ret = b''.join(ret) print(repr(ret)) ret = msgpack.unpackb(ret) print(repr(ret)) s = [1, 0, None, {b'get_valuesResponse': { b'get_valuesResult': [ {b"KeyValuePair": {b'key': b'a', b'value': b'b'}}, {b"KeyValuePair": {b'key': b'c', b'value': b'd'}}, ] }} ] print(s) assert ret == s
def test_mtom_join_envelope_chunks(self): FILE_NAME = 'EA055406-5881-4F02-A3DC-9A5A7510D018.dat' TNS = 'http://gib.gov.tr/vedop3/eFatura' # large enough payload to be chunked PAYLOAD = b"sample data " * 1024 class SomeService(Service): @rpc(Unicode(sub_name="fileName"), ByteArray(sub_name='binaryData'), ByteArray(sub_name="hash"), _returns=Unicode) def documentRequest(ctx, file_name, file_data, data_hash): assert file_name == FILE_NAME assert file_data == (PAYLOAD, ) return file_name app = Application([SomeService], tns=TNS, in_protocol=Soap12(), out_protocol=Soap12()) server = WsgiApplication(app, block_length=1024) response = etree.fromstring(b''.join( server( { 'QUERY_STRING': '', 'PATH_INFO': '/call', 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': 'Content-Type: multipart/related; ' 'type="application/xop+xml"; ' 'boundary="uuid:2e53e161-b47f-444a-b594-eb6b72e76997"; ' 'start="<*****@*****.**>"; ' 'start-info="application/soap+xml"; action="sendDocument"', 'wsgi.input': BytesIO( MTOM_REQUEST.replace(b"\n", b"\r\n").replace( b"sample data", PAYLOAD)), }, start_response, "http://null"))) response_str = etree.tostring(response, pretty_print=True) print(response_str) nsdict = dict(tns=TNS) assert etree.fromstring(response_str) \ .xpath(".//tns:documentRequestResult/text()", namespaces=nsdict) \ == [FILE_NAME]
def test_method_exception(self): from spyne.protocol.xml import XmlDocument h = [0] def on_method_exception_object(ctx): assert ctx.out_error is not None from spyne.protocol.xml import SchemaValidationError assert isinstance(ctx.out_error, SchemaValidationError) logging.error(repr(ctx.out_error)) h[0] += 1 class SomeService(Service): @rpc(Unicode(5)) def some_call(ctx, some_str): print(some_str) app = Application([SomeService], "some_tns", in_protocol=XmlDocument(validator='lxml'), out_protocol=Soap11()) app.event_manager.add_listener( "method_exception_object", on_method_exception_object) # this shouldn't be called because: # 1. document isn't validated # 2. hence; document can't be parsed # 3. hence; document can't be mapped to a function # 4. hence; document can't be mapped to a service class # 5. hence; no handlers from the service class is invoked. # 6. hence; the h[0] == 1 check (instead of 2) SomeService.event_manager.add_listener( "method_exception_object", on_method_exception_object) wsgi_app = WsgiApplication(app) xml_request = b""" <tns:some_call xmlns:tns="some_tns"> <tns:some_str>123456</tns:some_str> </tns:some_call> """ _ = b''.join(wsgi_app({ 'PATH_INFO': '/', 'SERVER_NAME': 'localhost', 'SERVER_PORT': '7000', 'REQUEST_METHOD': 'POST', 'wsgi.url_scheme': 'http', 'wsgi.input': BytesIO(xml_request), }, start_response)) assert h[0] == 1
def stream_factory(total_content_length, filename, content_type, content_length=None): if total_content_length >= SWAP_DATA_TO_FILE_THRESHOLD or \ delete == False: if delete == False: # You need python >= 2.6 for this. retval = tempfile.NamedTemporaryFile('wb+', dir=dir, delete=delete) else: retval = tempfile.NamedTemporaryFile('wb+', dir=dir) else: retval = BytesIO() return retval
def __run_service(self, service): app = Application([service], 'tns', in_protocol=HttpRpc(), out_protocol=Soap11()) server = WsgiApplication(app) return_string = b''.join(server({ 'QUERY_STRING': '', 'PATH_INFO': '/some_call', 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': 'text/xml; charset=utf8', 'SERVER_NAME': 'localhost', 'wsgi.input': BytesIO(b""), }, start_response, "http://null")) elt = etree.fromstring(return_string) print(etree.tostring(elt, pretty_print=True)) return elt, app.interface.nsmap
def setUp(self): self.ctx = FakeContext() self.stream = BytesIO() logging.basicConfig(level=logging.DEBUG)