Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

HttpRpc protocol got some love. #86

Merged
merged 23 commits into from

1 participant

Burak Arslan
Burak Arslan
Owner

No description provided.

Burak Arslan plq merged commit 202ebe5 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 11, 2011
  1. Burak Arslan
  2. Burak Arslan
  3. Burak Arslan
  4. Burak Arslan
  5. Burak Arslan

    fix soap mime type.

    plq authored
  6. Burak Arslan

    hard-code utf8 for soap.

    plq authored
  7. Burak Arslan

    XmlObject protocol does not distinguish between have header and body …

    plq authored
    …parts of a message, so move code from decompose_incoming_envelope function to create_in_document
  8. Burak Arslan

    test readme tweak.

    plq authored
  9. Burak Arslan
  10. Burak Arslan

    remove stray import.

    plq authored
  11. Burak Arslan
  12. Burak Arslan

    improve wording in comment

    plq authored
  13. Burak Arslan

    fix service tests.

    plq authored
  14. Burak Arslan

    add httprpc tests.

    plq authored
  15. Burak Arslan
  16. Burak Arslan
  17. Burak Arslan
  18. Burak Arslan
  19. Burak Arslan

    comment tweaks.

    plq authored
  20. Burak Arslan
  21. Burak Arslan

    add 'wsgi_method_not_found' event.

    plq authored
  22. Burak Arslan
  23. Burak Arslan

    changelog update

    plq authored
This page is out of date. Refresh to see the latest.
12 CHANGELOG.rst
View
@@ -2,6 +2,18 @@
Changelog
=========
+rpclib-2.3.1-beta
+-----------------
+ * HttpRpc protocol now returns 404 when a requested resource was not found.
+ * New tests added for HttpRpc protocol.
+ * Miscellanous other fixes.
+
+rpclib-2.3.0-beta
+-----------------
+ * Documentation improvements.
+ * rpclib.protocol.xml.XmlObject is now working as out_protocol.
+ * Many fixes.
+
rpclib-2.2.3-beta
------------------
* Documentation improvements.
6 src/rpclib/__init__.py
View
@@ -18,3 +18,9 @@
#
__version__ = '2.3.0-beta'
+
+from _base import TransportContext
+from _base import EventContext
+from _base import MethodContext
+from _base import MethodDescriptor
+from _base import EventManager
3  src/rpclib/error.py
View
@@ -0,0 +1,3 @@
+
+class NotFoundError(Exception):
+ """Raised when the requested resource was not found."""
13 src/rpclib/model/complex.py
View
@@ -24,10 +24,9 @@
import logging
logger = logging.getLogger(__name__)
-from lxml import etree
-
from rpclib.model import ModelBase
from rpclib.model import nillable_dict
+from rpclib.model import nillable_string
from rpclib.util.odict import odict as TypeInfo
from rpclib.const import xml_ns as namespace
@@ -223,6 +222,16 @@ def get_flat_type_info(clz, retval={}):
return retval
@classmethod
+ @nillable_string
+ def to_string(cls, value):
+ raise ValueError("Only primitives can be serialized to string.")
+
+ @classmethod
+ @nillable_string
+ def from_string(cls, string):
+ raise ValueError("Only primitives can be deserialized from string.")
+
+ @classmethod
@nillable_dict
def from_dict(cls, in_dict):
inst = cls.get_deserialization_instance()
1  src/rpclib/protocol/__init__.py
View
@@ -18,4 +18,3 @@
#
from _base import ProtocolBase
-from _base import ValidationError
14 src/rpclib/protocol/_base.py
View
@@ -30,10 +30,8 @@
_ns_xsd = rpclib.const.xml_ns.xsd
from rpclib._base import EventManager
-from rpclib.model.fault import Fault
-
-class ValidationError(Fault):
- pass
+from rpclib.error import NotFoundError
+# from pprint import pformat
class ProtocolBase(object):
"""This is the abstract base class for all protocol implementations. Child
@@ -105,10 +103,10 @@ def set_method_descriptor(self, ctx):
ctx.service_class = self.app.interface.service_mapping.get(name, None)
if ctx.service_class is None:
- logger.debug(self.app.interface.service_mapping.keys())
- raise Exception('Method %r not bound to a service class.' % name)
+ # logger.debug(pformat(self.app.interface.service_mapping.keys()))
+ raise NotFoundError('Method %r not bound to a service class.' % name)
ctx.descriptor = ctx.app.interface.method_mapping.get(name, None)
if ctx.descriptor is None:
- logger.debug(ctx.app.interface.method_mapping.keys())
- raise Exception('Method %r not found.' % name)
+ # logger.debug(pformat(ctx.app.interface.method_mapping.keys()))
+ raise NotFoundError('Method %r not found.' % name)
46 src/rpclib/protocol/http.py
View
@@ -22,10 +22,23 @@
import logging
logger = logging.getLogger(__name__)
-from rpclib.protocol import ProtocolBase
import urlparse
+from rpclib.error import NotFoundError
+from rpclib.server.wsgi import HTTP_404
+from rpclib.protocol import ProtocolBase
+
# this is not exactly rest, because it ignores http verbs.
+
+def _get_http_headers(req_env):
+ retval = {}
+
+ for k,v in req_env.iteritems():
+ if k.startswith("HTTP_"):
+ retval[k[5:].lower()]= v
+
+ return retval
+
class HttpRpc(ProtocolBase):
"""The so-called ReST-minus-the-verbs HttpRpc protocol implementation.
It only works with the http server (wsgi) transport.
@@ -42,9 +55,13 @@ def create_in_document(self, ctx, in_string_encoding=None):
ctx.transport.req_env['PATH_INFO'].split('/')[-1])
logger.debug("\033[92mMethod name: %r\033[0m" % ctx.method_request_string)
- self.app.in_protocol.set_method_descriptor(ctx)
+ try:
+ self.app.in_protocol.set_method_descriptor(ctx)
+ except NotFoundError, e:
+ ctx.transport.resp_code = HTTP_404
+ raise
- ctx.in_header_doc = None
+ ctx.in_header_doc = _get_http_headers(ctx.transport.req_env)
ctx.in_body_doc = urlparse.parse_qs(ctx.transport.req_env['QUERY_STRING'])
logger.debug(repr(ctx.in_body_doc))
@@ -62,25 +79,20 @@ def deserialize(self, ctx):
def serialize(self, ctx):
result_message_class = ctx.descriptor.out_message
- result_message = result_message_class()
# assign raw result to its wrapper, result_message
out_type_info = result_message_class._type_info
- if len(out_type_info) > 0:
- if len(out_type_info) == 1:
- attr_name = result_message_class._type_info.keys()[0]
- setattr(result_message, attr_name, ctx.out_object)
-
- else:
- for i in range(len(out_type_info)):
- attr_name=result_message_class._type_info.keys()[i]
- setattr(result_message, attr_name, ctx.out_object[i])
+ if len(out_type_info) == 1:
+ out_class = out_type_info.values()[0]
+ if ctx.out_object is None:
+ ctx.out_document = u''
+ else:
+ ctx.out_document = out_class.to_string(ctx.out_object)
- wrapped_result = result_message_class.to_dict(result_message)
-
- ctx.out_document, = wrapped_result.itervalues()
+ else:
+ raise ValueError("HttpRpc protocol can only serialize primitives.")
self.event_manager.fire_event('serialize', ctx)
def create_out_string(self, ctx, out_string_encoding=None):
- ctx.out_string = ctx.out_document
+ ctx.out_string = [ctx.out_document.encode('utf8')]
7 src/rpclib/protocol/soap/soap11.py
View
@@ -34,7 +34,6 @@
from rpclib.protocol.soap.mime import collapse_swa
from rpclib.model.fault import Fault
-from rpclib.model.primitive import string_encoding
class ValidationError(Fault):
pass
@@ -71,7 +70,7 @@ def _from_soap(in_envelope_xml, xmlids=None):
def _parse_xml_string(xml_string, charset=None):
try:
if charset is None:
- charset = string_encoding
+ charset = 'utf-8'
root, xmlids = etree.XMLID(xml_string.decode(charset))
@@ -130,7 +129,7 @@ class OUT_WRAPPER:
pass
allowed_http_verbs = ['POST']
- mime_type = 'application/soap+xml'
+ mime_type = 'text/xml; charset=utf-8'
def __init__(self, app=None):
XmlObject.__init__(self, app)
@@ -149,7 +148,7 @@ def create_in_document(self, ctx, charset=None):
def create_out_string(self, ctx, charset=None):
"""Sets an iterable of string fragments to ctx.out_string"""
if charset is None:
- charset = string_encoding
+ charset = 'utf-8'
ctx.out_string = [etree.tostring(ctx.out_document, xml_declaration=True,
encoding=charset)]
22 src/rpclib/protocol/xml/_base.py
View
@@ -26,6 +26,7 @@
from rpclib.util.cdict import cdict
+from rpclib.error import NotFoundError
from rpclib.model import ModelBase
from rpclib.model.complex import Array
@@ -82,10 +83,6 @@
EnumBase: enum_from_element,
})
-class NotFoundError(Exception):
- """Raised when the requested resource was not found."""
- pass
-
class XmlObject(ProtocolBase):
def from_element(self, cls, element):
handler = _deserialization_handlers[cls]
@@ -98,15 +95,6 @@ def to_parent_element(self, cls, value, tns, parent_elt, * args, ** kwargs):
def create_in_document(self, ctx, charset=None):
ctx.in_document = etree.fromstring(ctx.in_string, charset)
- def create_out_string(self, ctx, charset=None):
- """Sets an iterable of string fragments to ctx.out_string"""
- if charset is None:
- charset = 'utf8'
-
- ctx.out_string = [etree.tostring(ctx.out_document, xml_declaration=True,
- encoding=charset)]
-
- def decompose_incoming_envelope(self, ctx):
body_doc = ctx.in_document
try:
@@ -146,6 +134,14 @@ def decompose_incoming_envelope(self, ctx):
# payload. That's SOAP's job to do.
ctx.in_body_doc = body_doc
+ def create_out_string(self, ctx, charset=None):
+ """Sets an iterable of string fragments to ctx.out_string"""
+ if charset is None:
+ charset = 'utf8'
+
+ ctx.out_string = [etree.tostring(ctx.out_document, xml_declaration=True,
+ encoding=charset)]
+
def deserialize(self, ctx, way='out'):
"""Takes a MethodContext instance and a string containing ONE root xml
tag.
9 src/rpclib/server/_base.py
View
@@ -26,12 +26,6 @@
from rpclib.model.fault import Fault
from rpclib._base import EventManager
-class InternalError(Fault):
- pass
-
-class ValidationError(Fault):
- pass
-
class ServerBase(object):
"""This class is the abstract base class for all server transport
implementations. Unlike the client transports, this class does not define
@@ -102,3 +96,6 @@ def get_out_string(self, ctx):
else:
ctx.service_class.event_manager.fire_event(
'method_exception_string', ctx)
+
+ if ctx.out_string is None:
+ ctx.out_string = [""]
76 src/rpclib/server/wsgi.py
View
@@ -26,8 +26,10 @@
import cgi
-from rpclib._base import MethodContext
-from rpclib.model.fault import Fault
+from rpclib import TransportContext
+from rpclib import MethodContext
+
+from rpclib.error import NotFoundError
from rpclib.protocol.soap.mime import apply_mtom
from rpclib.util import reconstruct_url
from rpclib.server import ServerBase
@@ -59,18 +61,25 @@ def reconstruct_wsgi_request(http_env):
return input.read(length), charset
-class WsgiMethodContext(MethodContext):
- def __init__(self, app, req_env, content_type):
- MethodContext.__init__(self, app)
+class WsgiTransportContext(TransportContext):
+ def __init__(self, req_env, content_type):
+ TransportContext.__init__(self, 'wsgi')
- self.transport.type = 'wsgi'
- self.transport.req_env = req_env
- self.transport.resp_headers = {
+ self.req_env = req_env
+ self.resp_headers = {
'Content-Type': content_type,
'Content-Length': '0',
}
- self.transport.req_method = req_env.get('REQUEST_METHOD', None)
- self.transport.wsdl_error = None
+ self.resp_code = None
+ self.req_method = req_env.get('REQUEST_METHOD', None)
+ self.wsdl_error = None
+
+
+class WsgiMethodContext(MethodContext):
+ def __init__(self, app, req_env, content_type):
+ MethodContext.__init__(self, app)
+
+ self.transport = WsgiTransportContext(req_env, content_type)
class WsgiApplication(ServerBase):
@@ -108,7 +117,7 @@ def __call__(self, req_env, start_response, wsgi_url=None):
def __is_wsdl_request(self, req_env):
# Get the wsdl for the service. Assume path_info matches pattern:
# /stuff/stuff/stuff/serviceName.wsdl or
- # /stuff/stuff/stuff/serviceName/?wsdl
+ # /stuff/stuff/stuff/serviceName/?wsdl with anything between ? and wsdl.
return (
req_env['REQUEST_METHOD'].lower() == 'get'
@@ -119,7 +128,7 @@ def __is_wsdl_request(self, req_env):
)
def __handle_wsdl_request(self, req_env, start_response, url):
- ctx = WsgiMethodContext(self.app, req_env, 'text/xml')
+ ctx = WsgiMethodContext(self.app, req_env, 'text/xml; charset=utf-8')
try:
wsdl = self.app.interface.get_interface_document()
@@ -155,34 +164,45 @@ def __handle_rpc(self, req_env, start_response):
ctx.in_string, in_string_charset = reconstruct_wsgi_request(req_env)
- self.get_in_object(ctx, in_string_charset)
+ try:
+ self.get_in_object(ctx, in_string_charset)
+ except NotFoundError, e:
+ pass
- return_code = HTTP_200
if ctx.in_error:
out_object = ctx.in_error
- return_code = HTTP_500
+ if ctx.transport.resp_code is None:
+ ctx.transport.resp_code = HTTP_500
else:
if ctx.service_class == None:
- start_response(HTTP_404, ctx.transport.resp_headers.items())
- return ['']
+ if ctx.transport.resp_code is None:
+ ctx.transport.resp_code = HTTP_500
+
+ ctx.out_string = [ctx.transport.resp_code]
+
+ self.event_manager.fire_event('wsgi_method_not_found', ctx)
+
+ start_response(ctx.transport.resp_code, ctx.transport.resp_headers.items())
+ return ctx.out_string
self.get_out_object(ctx)
- if not (ctx.out_error is None):
- return_code = HTTP_500
+ if ctx.out_error is None:
+ ctx.transport.resp_code = HTTP_200
+ else:
+ ctx.transport.resp_code = HTTP_500
self.get_out_string(ctx)
- if ctx.out_string is None:
- ctx.out_string = [""]
# implementation hook
self.event_manager.fire_event('wsgi_return', ctx)
if ctx.descriptor and ctx.descriptor.mtom:
- # when there are more than one return type, the result is
+ # when there is more than one return type, the result is
# encapsulated inside a list. when there's just one, the result
- # is returned unencapsulated. the apply_mtom always expects the
- # objects to be inside an iterable, hence the following test.
+ # is returned in a non-encapsulated form. the apply_mtom always
+ # expects the objects to be inside an iterable, hence the following
+ # test.
out_type_info = ctx.descriptor.out_message._type_info
if len(out_type_info) == 1:
out_object = [out_object]
@@ -193,8 +213,12 @@ def __handle_rpc(self, req_env, start_response):
out_object
)
- # initiate the response
+ # We can't set the content-length if we want to support any kind of
+ # python iterable as output. We can't iterate and count, that defeats
+ # the whole point.
del ctx.transport.resp_headers['Content-Length']
- start_response(return_code, ctx.transport.resp_headers.items())
+
+ # initiate the response
+ start_response(ctx.transport.resp_code, ctx.transport.resp_headers.items())
return ctx.out_string
29 src/rpclib/test/README
View
@@ -12,13 +12,23 @@ detect such corner cases is to have a great test suite.
Requirements
------------
-While the stock unittest package is normally enough to run Python tests, using
-py.test from pytest package is just a more pleasant way to run them. Simply
-easy_install pytest to get it. You can run the following command in the test
-directory: ::
+While simply executing test modules is normally enough to run Python tests,
+using py.test from pytest package is just a more pleasant way to run them.
+Simply easy_install pytest to get it. You can run the following command in the
+test directory: ::
py.test -v --tb=short
+You can use the module name as an argument: ::
+
+ py.test -v --tb=short test_sqla.py
+
+You can also choose which test to run: ::
+
+ py.test -v --tb=short test_sqla.py -k test_same_table_inheritance
+
+See [pytest documentation](http://pytest.org/latest/) for more info.
+
Note that you need to do several other preparations to have the interop tests
working. See the next section for the specifics.
@@ -28,6 +38,15 @@ Interoperability Tests
The interoperability servers require twisted.web.
+.Python
+^^^^^^^
+
+Python interop tests currently use Rpclib's own clients and suds. The suds test
+is the first thing we check and try not to break.
+
+Two tests that fail in the suds interop tests due to the lack of proper assert
+statements, so they're false alarms.
+
.Net
^^^^
@@ -78,5 +97,3 @@ Here's the directory tree from a working setup:
| |-- README.txt
| `-- (...)
`-- (...)
-
-
2  src/rpclib/test/interop/server/httprpc_pod_basic.py
View
@@ -41,7 +41,7 @@
wsgi_application = WsgiApplication(httprpc_soap_application)
server = make_server('0.0.0.0', 9757, validator(wsgi_application))
- logger.info('Starting interop server at %s:%s.' % ('0.0.0.0', 9756))
+ logger.info('Starting interop server at %s:%s.' % ('0.0.0.0', 9757))
logger.info('WSDL is at: /?wsdl')
server.serve_forever()
86 src/rpclib/test/interop/test_httprpc.py
View
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+#
+# rpclib - Copyright (C) Rpclib contributors.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+#
+
+import pytz
+import unittest
+import urllib
+import urllib2
+
+from datetime import datetime
+
+class TestHttpRpc(unittest.TestCase):
+ def test_404(self):
+ url = 'http://localhost:9757/404'
+ try:
+ data = urllib2.urlopen(url).read()
+ except urllib2.HTTPError, e:
+ assert e.code == 404
+
+ def test_500(self):
+ url = 'http://localhost:9757/python_exception'
+ try:
+ data = urllib2.urlopen(url).read()
+ except urllib2.HTTPError, e:
+ assert e.code == 500
+
+ def test_500_2(self):
+ url = 'http://localhost:9757/soap_exception'
+ try:
+ data = urllib2.urlopen(url).read()
+ except urllib2.HTTPError, e:
+ assert e.code == 500
+
+ def test_echo_string(self):
+ url = 'http://localhost:9757/echo_string?s=punk'
+ data = urllib2.urlopen(url).read()
+
+ assert data == 'punk'
+
+ def test_echo_integer(self):
+ url = 'http://localhost:9757/echo_integer?i=444'
+ data = urllib2.urlopen(url).read()
+
+ assert data == '444'
+
+ def test_echo_datetime(self):
+ dt = datetime.now().isoformat()
+ params = urllib.urlencode({
+ 'dt': dt,
+ })
+
+ print params
+ url = 'http://localhost:9757/echo_datetime?%s' % str(params)
+ data = urllib2.urlopen(url).read()
+
+ assert dt == data
+
+ def test_echo_datetime_tz(self):
+ dt = datetime.now(pytz.utc).isoformat()
+ params = urllib.urlencode({
+ 'dt': dt,
+ })
+
+ print params
+ url = 'http://localhost:9757/echo_datetime?%s' % str(params)
+ data = urllib2.urlopen(url).read()
+
+ assert dt == data
+
+if __name__ == '__main__':
+ unittest.main()
5 src/rpclib/test/interop/test_suds.py
View
@@ -62,10 +62,11 @@ def test_validation(self):
non_nillable_class.s = None
try:
- ret = self.client.service.non_nillable(non_nillable_class)
- raise Exception("must fail")
+ self.client.service.non_nillable(non_nillable_class)
except WebFault, e:
pass
+ else:
+ raise Exception("must fail")
def test_echo_integer_array(self):
ia = self.client.factory.create('integerArray')
104 src/rpclib/test/protocol/test_http.py
View
@@ -0,0 +1,104 @@
+
+#!/usr/bin/env python
+#
+# rpclib - Copyright (C) Rpclib contributors.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+#
+
+import logging
+logging.basicConfig(level=logging.DEBUG)
+
+import unittest
+
+from rpclib.application import Application
+from rpclib.decorator import srpc
+from rpclib.model.primitive import Integer
+from rpclib.model.primitive import String
+from rpclib.model.complex import ComplexModel
+from rpclib.interface.wsdl import Wsdl11
+from rpclib.protocol.http import HttpRpc
+from rpclib.protocol.soap import Soap11
+from rpclib.service import ServiceBase
+
+class Test(unittest.TestCase):
+ '''Most of the service tests are performed through the interop tests.'''
+
+ def test_multiple_return(self):
+ class SomeNotSoComplexModel(ComplexModel):
+ s = String
+
+ class SomeService(ServiceBase):
+ @srpc(_returns=[Integer, String])
+ def some_call():
+ return 1,'s'
+
+ app = Application([SomeService], 'tns', Wsdl11(), HttpRpc(), HttpRpc())
+
+ from rpclib.server.wsgi import WsgiMethodContext
+
+ ctx = WsgiMethodContext(app,{
+ 'QUERY_STRING': '',
+ 'PATH_INFO': '/some_call',
+ }, 'some-content-type')
+
+ from rpclib.server import ServerBase
+
+ server = ServerBase(app)
+ try:
+ server.get_in_object(ctx)
+ server.get_out_object(ctx)
+ server.get_out_string(ctx)
+ except ValueError:
+ pass
+ else:
+ raise Exception("Must Fail")
+
+ def test_primitive_only(self):
+ class SomeComplexModel(ComplexModel):
+ i = Integer
+ s = String
+
+ class SomeService(ServiceBase):
+ @srpc(SomeComplexModel, _returns=SomeComplexModel)
+ def some_call(scm):
+ return SomeComplexModel(i=5,s='5x')
+
+ app = Application([SomeService], 'tns', Wsdl11(), HttpRpc(), HttpRpc())
+
+ from rpclib.server.wsgi import WsgiMethodContext
+
+ ctx = WsgiMethodContext(app,{
+ 'QUERY_STRING': '',
+ 'PATH_INFO': '/some_call',
+ }, 'some-content-type')
+
+ from rpclib.server import ServerBase
+
+ server = ServerBase(app)
+
+ try:
+ server.get_in_object(ctx)
+ server.get_out_object(ctx)
+ server.get_out_string(ctx)
+ except ValueError:
+ pass
+ else:
+ raise Exception("Must Fail")
+
+
+
+if __name__ == '__main__':
+ unittest.main()
51 src/rpclib/test/test_service.py
View
@@ -17,11 +17,14 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
#
+#
+# Most of the service tests are performed through the interop tests.
+#
import datetime
import unittest
-import rpclib.interface.wsdl
-import rpclib.protocol.soap
+from rpclib.interface.wsdl import Wsdl11
+from rpclib.protocol.soap import Soap11
from lxml import etree
@@ -124,55 +127,49 @@ class MultipleReturnService(ServiceBase):
def multi(self, s):
return s, 'a', 'b'
-class Test(unittest.TestCase):
- '''Most of the service tests are performed through the interop tests.'''
-
- def _set_up(self):
- self.app = Application([TestService], rpclib.interface.wsdl.Wsdl11,
- rpclib.protocol.soap.Soap11, tns='tns')
+class TestSingle(unittest.TestCase):
+ def setUp(self):
+ self.app = Application([TestService], 'tns', Wsdl11(), Soap11(), Soap11())
self.srv = TestService()
+
self.app.interface.build_interface_document('URL')
- self._wsdl = self.app.interface.get_interface_document()
- self.wsdl = etree.fromstring(self._wsdl)
+ self.wsdl_str = self.app.interface.get_interface_document()
+ self.wsdl_doc = etree.fromstring(self.wsdl_str)
def test_portypes(self):
- self._set_up()
-
- porttype = self.wsdl.find('{http://schemas.xmlsoap.org/wsdl/}portType')
+ porttype = self.wsdl_doc.find('{http://schemas.xmlsoap.org/wsdl/}portType')
self.assertEquals(
len(self.srv.public_methods), len(porttype.getchildren()))
def test_override_param_names(self):
- self._set_up()
+ # FIXME: This test must be rewritten.
for n in ['self', 'import', 'return', 'from']:
- self.assertTrue(n in self._wsdl, '"%s" not in self._wsdl' % n)
+ self.assertTrue(n in self.wsdl_str, '"%s" not in self.wsdl_str' % n)
+
+class TestMultiple(unittest.TestCase):
+ def setUp(self):
+ self.app = Application([MultipleReturnService], 'tns', Wsdl11(), Soap11(), Soap11())
+ self.app.interface.build_interface_document('url')
def test_multiple_return(self):
- app = Application([MultipleReturnService], rpclib.interface.wsdl.Wsdl11,
- rpclib.protocol.soap.Soap11, tns='tns')
- app.interface.build_interface_document('url')
- srv = MultipleReturnService()
- message = srv.public_methods.values()[0].out_message()
+ message_class = MultipleReturnService.public_methods.values()[0].out_message
+ message = message_class()
self.assertEquals(len(message._type_info), 3)
sent_xml = etree.Element('test')
- message.to_parent_element( ('a','b','c'), srv.get_tns(), sent_xml )
+ self.app.out_protocol.to_parent_element(message_class, ('a','b','c'),
+ MultipleReturnService.get_tns(), sent_xml)
sent_xml = sent_xml[0]
print etree.tostring(sent_xml, pretty_print=True)
- response_data = message.from_xml(sent_xml)
+ response_data = self.app.out_protocol.from_element(message_class, sent_xml)
self.assertEquals(len(response_data), 3)
self.assertEqual(response_data[0], 'a')
self.assertEqual(response_data[1], 'b')
self.assertEqual(response_data[2], 'c')
- def test_multiple_ns(self):
- svc = Application([MultipleNamespaceService],rpclib.interface.wsdl.Wsdl11,
- rpclib.protocol.soap.Soap11,tns='tns')
- svc.interface.get_interface_document()
-
if __name__ == '__main__':
unittest.main()
Something went wrong with that request. Please try again.