ladon-dev-team team mailing list archive
-
ladon-dev-team team
-
Mailing list archive
-
Message #00037
[Merge] lp:~roger-lp/ladon/trunk into lp:ladon
roger has proposed merging lp:~roger-lp/ladon/trunk into lp:ladon.
Requested reviews:
Mikhus (mikhus)
For more details, see:
https://code.launchpad.net/~roger-lp/ladon/trunk/+merge/131028
Contains implementation of JSON-RPC 1.0 specification for request and response, notifications hasn't implemented yet. Also contains fix for python 3.3 __qualname__ (PEP 3155 -- Qualified name for classes and functions).
--
https://code.launchpad.net/~roger-lp/ladon/trunk/+merge/131028
Your team Ladon Developer is subscribed to branch lp:ladon.
=== modified file 'frameworks/python/src/ladon/interfaces/__init__.py'
--- frameworks/python/src/ladon/interfaces/__init__.py 2012-05-04 14:43:58 +0000
+++ frameworks/python/src/ladon/interfaces/__init__.py 2012-10-23 15:04:45 +0000
@@ -71,3 +71,4 @@
import ladon.interfaces.soap
import ladon.interfaces.soap11
import ladon.interfaces.jsonwsp
+import ladon.interfaces.jsonrpc10
=== modified file 'frameworks/python/src/ladon/interfaces/base.py'
--- frameworks/python/src/ladon/interfaces/base.py 2012-01-06 12:44:37 +0000
+++ frameworks/python/src/ladon/interfaces/base.py 2012-10-23 15:04:45 +0000
@@ -81,6 +81,12 @@
def description_content_type(self):
return self._service_descriptor._content_type
+
+ def get_passback_params(self,req_dict):
+ return self._request_handler.get_passback_params(req_dict)
+
+ def add_passback_params(self,res_dict,passback_dict):
+ return self._fault_handler.add_passback_params(res_dict,passback_dict)
class ServiceDescriptor(object):
@@ -108,6 +114,9 @@
def parse_request(self,req,sinfo,encoding):
return {}
+
+ def get_passback_params(self,req_dict):
+ return {}
class BaseResponseHandler(object):
@@ -127,6 +136,9 @@
def build_response(self,method_result,sinfo,encoding):
return ''
+
+ def add_passback_params(self,res_dict,passback_dict):
+ return res_dict
class BaseFaultHandler(object):
@@ -145,3 +157,6 @@
def build_fault_response(self,exc,sinfo,methodname,encoding):
return ''
+
+ def add_passback_params(self,res_dict,passback_dict):
+ return res_dict
=== added file 'frameworks/python/src/ladon/interfaces/jsonrpc10.py'
--- frameworks/python/src/ladon/interfaces/jsonrpc10.py 1970-01-01 00:00:00 +0000
+++ frameworks/python/src/ladon/interfaces/jsonrpc10.py 2012-10-23 15:04:45 +0000
@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+
+from ladon.interfaces.base import BaseInterface,ServiceDescriptor,BaseRequestHandler,BaseResponseHandler,BaseFaultHandler
+from ladon.interfaces import expose
+from ladon.compat import type_to_jsontype,pytype_support,PORTABLE_STRING
+import json,sys,traceback
+from ladon.exceptions.service import ServiceFault
+from ladon.exceptions.base import LadonException
+
+def _add_passback_params(res_dict,passback_dict):
+ merged_dict = dict((k,v) for (k,v) in res_dict.items())
+ for k,v in passback_dict.items():
+ merged_dict[k] = v
+ return merged_dict
+
+class RequestPropFault(ServiceFault):
+ def __init__(self,prop, passback_dict):
+ self.prop = prop
+ self.passback_dict = passback_dict
+ super(RequestPropFault,self).__init__('service','Request doesn\'t have "%s" property.' % self.prop, None, 2)
+
+ def __str__(self):
+ return self.faultstring
+
+class RequestParamFault(ServiceFault):
+ def __init__(self,param, passback_dict):
+ self.param = param
+ self.passback_dict = passback_dict
+ super(RequestParamFault,self).__init__('service','Request doesn\'t have "%s" parameter.' % self.param, None, 2)
+
+ def __str__(self):
+ return self.faultstring
+
+class JSONRPCServiceDescriptor(ServiceDescriptor):
+ javascript_type_map = type_to_jsontype
+ version = '1.0'
+ _content_type = 'application/json'
+
+ def generate(self,servicename,servicenumber,typemanager,methodlist,service_url,encoding):
+ type_dict = typemanager.type_dict
+ type_order = typemanager.type_order
+
+ def map_type(typ):
+ if typ in JSONRPCServiceDescriptor.javascript_type_map:
+ return JSONRPCServiceDescriptor.javascript_type_map[typ]
+ else:
+ return typ.__name__
+
+ desc = {
+ 'servicename': servicename,
+ 'url': service_url,
+ 'type': 'jsonrpc/description',
+ 'version': self.version,
+ 'types': {},
+ 'methods': {}
+ }
+
+ types = desc['types']
+ for typ in type_order:
+ if type(typ)==dict:
+ desc_type = {}
+ types[typ['name']] = desc_type
+ for k,v,props in typ['attributes']:
+ if type(v)==list:
+ desc_type_val = [map_type(v[0])]
+ else:
+ desc_type_val = map_type(v)
+ desc_type[k] = desc_type_val
+
+ methods = desc['methods']
+ for m in methodlist:
+ desc_mparams = {}
+ order = 1
+ desc_method = {'params': desc_mparams, 'doc_lines': m._method_doc}
+ methods[m.name()] = desc_method
+ for arg in m.args():
+ if [list,tuple].count(type(arg['type'])):
+ desc_param_type = [map_type(arg['type'][0])]
+ else:
+ desc_param_type = map_type(arg['type'])
+ desc_mparams[arg['name']] = {
+ "type": desc_param_type,
+ "def_order": order,
+ "optional": arg['optional'],
+ }
+ if 'doc' in arg:
+ desc_mparams[arg['name']]["doc_lines"] = arg['doc']
+ else:
+ desc_mparams[arg['name']]["doc_lines"] = []
+ order += 1
+
+ if [list,tuple].count(type(m._rtype)):
+ desc_rtype = [map_type(m._rtype[0])]
+ else:
+ desc_rtype = map_type(m._rtype)
+ desc_method['ret_info'] = {
+ 'type': desc_rtype,
+ 'doc_lines': m._rtype_doc
+ }
+
+ if sys.version_info[0]>=3:
+ return json.dumps(desc)
+ return json.dumps(desc,encoding=encoding)
+
+class JSONRPCRequestHandler(BaseRequestHandler):
+ def parse_request(self,json_body,sinfo,encoding):
+ def parse_number(x):
+ return PORTABLE_STRING(x)
+ def parse_constant(x):
+ if x=='null':
+ return PORTABLE_STRING("None")
+ return PORTABLE_STRING(x)
+ req_dict = json.loads(PORTABLE_STRING(json_body,encoding), parse_int=parse_number, parse_float=parse_number, \
+ parse_constant=parse_constant)
+ passback_dict = self.get_passback_params(req_dict)
+ if 'method' not in req_dict:
+ raise RequestPropFault('method',passback_dict)
+ if 'params' not in req_dict:
+ raise RequestPropFault('params',passback_dict)
+ if 'id' not in req_dict:
+ raise RequestPropFault('id',passback_dict)
+ minfo = sinfo.methods[req_dict['method']]
+ if (req_dict['params'] is None or len(req_dict['params']) == 0) and len(minfo.args()) > 0:
+ raise RequestParamFault(minfo.args()[0]['name'],passback_dict)
+ else:
+ for arg in minfo.args():
+ isgiven = False
+ for param in req_dict['params']:
+ if param == arg['name']:
+ isgiven = True
+ if not isgiven:
+ raise RequestParamFault(arg['name'],passback_dict)
+ req_dict['args'] = req_dict['params']
+ del req_dict['params']
+ return req_dict
+
+ def get_passback_params(self, req_dict):
+ if 'id' in req_dict:
+ return {'id': req_dict['id']}
+ else:
+ return {}
+
+class JSONRPCResponseHandler(BaseResponseHandler):
+ _content_type = 'application/json'
+ _stringify_res_dict = False
+
+ def build_response(self,res_dict,sinfo,encoding):
+ res_dict['error'] = None
+ del res_dict['servicenumber']
+ del res_dict['servicename']
+ del res_dict['method']
+ return json.dumps(res_dict,ensure_ascii=False).encode(encoding)
+
+ def add_passback_params(self,res_dict,passback_dict):
+ return _add_passback_params(res_dict,passback_dict)
+
+class JSONRPCFaultHandler(BaseFaultHandler):
+ _content_type = 'application/json'
+ _stringify_res_dict = False
+
+ def build_fault_response(self,service_exc,sinfo,methodname,encoding):
+ if service_exc.detail:
+ detail = service_exc.detail
+ else:
+ detail = traceback.format_exc()
+ detail = detail.replace('\r\n','\n').split('\n')
+ fault_dict = {
+ 'result': None,
+ 'error': {
+ 'code': service_exc.faultcode,
+ 'string': service_exc.faultstring,
+ 'detail': detail,
+ 'filename': service_exc.mod,
+ 'lineno': service_exc.lineno
+ },
+ }
+ if hasattr(service_exc,'passback_dict'):
+ fault_dict = self.add_passback_params(fault_dict,service_exc.passback_dict)
+ return json.dumps(fault_dict,ensure_ascii=False).encode(encoding)
+
+ def add_passback_params(self, res_dict, passback_dict):
+ return _add_passback_params(res_dict,passback_dict)
+
+@expose
+class JSONRPCInterface(BaseInterface):
+ def __init__(self,sinfo,**kw):
+ def_kw = {
+ 'service_descriptor': JSONRPCServiceDescriptor,
+ 'request_handler': JSONRPCRequestHandler,
+ 'response_handler': JSONRPCResponseHandler,
+ 'fault_handler': JSONRPCFaultHandler}
+ def_kw.update(kw)
+ BaseInterface.__init__(self,sinfo,**def_kw)
+
+ @staticmethod
+ def _interface_name():
+ return 'jsonrpc10'
+
+ @staticmethod
+ def _accept_basetype(typ):
+ return pytype_support.count(typ)>0
+
+ @staticmethod
+ def _accept_list():
+ return True
+
+ @staticmethod
+ def _accept_dict():
+ return False
\ No newline at end of file
=== modified file 'frameworks/python/src/ladon/server/dispatcher.py'
--- frameworks/python/src/ladon/server/dispatcher.py 2012-09-05 12:39:33 +0000
+++ frameworks/python/src/ladon/server/dispatcher.py 2012-10-23 15:04:45 +0000
@@ -37,7 +37,7 @@
self.logging = logging
- def call_method(self,method,req_dict,tc,export_dict,log_line):
+ def call_method(self,methodname,method,req_dict,tc,export_dict,log_line):
"""
call_method converts the res_dict delivered from an interface
to the type of arguments expected by the service method.
@@ -83,7 +83,7 @@
#service_module = imp.load_module(mname,file, pathname, description)
service_class_instance = getattr(service_module,method.sinfo.servicename)()
if self.logging & LOG_REQUEST_ACCESS:
- log_line += ['Method:%s.%s' % (method.sinfo.servicename,req_dict['methodname'])]
+ log_line += ['Method:%s.%s' % (method.sinfo.servicename,methodname)]
if self.logging & LOG_REQUEST_DICT:
log_line += ['RequestDict:%s' % (str(req_dict))]
if self.logging & LOG_EXECUTION_TIME:
@@ -91,9 +91,9 @@
if method._has_keywords:
kw = {'LADON_METHOD_TC':tc}
kw.update(export_dict)
- result = getattr(service_class_instance,req_dict['methodname'])(*args,**kw)
+ result = getattr(service_class_instance,methodname)(*args,**kw)
else:
- result = getattr(service_class_instance,req_dict['methodname'])(*args)
+ result = getattr(service_class_instance,methodname)(*args)
if self.logging & LOG_EXECUTION_TIME:
log_line.insert(0,'ExecutionTime:%s' % str(time.time()-start))
return result
@@ -148,7 +148,8 @@
export_dict['response_attachments'] = AttachmentHandler()
methodname,method = None,None
req_dict = self.iface.parse_request(request_data,encoding=self.response_encoding)
- methodname = req_dict['methodname']
+ passback_dict = self.iface.get_passback_params(req_dict)
+ methodname = req_dict['methodname'] if 'methodname' in req_dict else req_dict['method']
method = self.sinst.method(methodname)
if not method:
raise UndefinedServiceMethod(self.iface._interface_name(),self.sinst.servicename,'Service method "%s" is not declared in service' % methodname)
@@ -156,7 +157,7 @@
encoding=method._encoding,
allow_unsafe_conversion=method._allow_unsafe_conversion,
only_strings_to_unicode=(not self.iface.stringify_res_dict()))
- result = self.call_method(method,req_dict,tc,export_dict,log_line)
+ result = self.call_method(methodname,method,req_dict,tc,export_dict,log_line)
except Exception as e:
if isinstance(e,ServiceFault):
response = self.iface.build_fault_response(e,methodname,encoding=self.response_encoding)
@@ -176,9 +177,10 @@
# so the service developer has full control over response headers and data.
return result
res_dict = self.result_to_dict(method,result,tc,export_dict['response_attachments'],log_line=log_line)
+ res_dict = self.iface.add_passback_params(res_dict, passback_dict)
if 'mirror' in req_dict:
res_dict['reflection'] = req_dict['mirror']
response = self.iface.build_response(res_dict,encoding=self.response_encoding)
if self.logging:
- debug('\t%s' % ('\t'.join(log_line)))
+ debug('\t%s' % ('\t'.join(log_line)))
return response
=== modified file 'frameworks/python/src/ladon/types/typemanager.py'
--- frameworks/python/src/ladon/types/typemanager.py 2012-01-28 14:40:18 +0000
+++ frameworks/python/src/ladon/types/typemanager.py 2012-10-23 15:04:45 +0000
@@ -9,7 +9,9 @@
this_cls_attrs = dir(cls)
res = []
for attr in this_cls_attrs:
- if base_attrs.count(attr) or (exclude_methods and inspect.ismethod(getattr(cls,attr))):
+ # attr == '__qualname__'
+ # Python 3.3 __qualname__ (PEP 3155 -- Qualified name for classes and functions) fix
+ if base_attrs.count(attr) or (exclude_methods and inspect.ismethod(getattr(cls,attr))) or attr == '__qualname__':
continue
res += [attr]
return res
=== modified file 'frameworks/python/tests/servicerunner.py'
--- frameworks/python/tests/servicerunner.py 2012-10-15 15:05:09 +0000
+++ frameworks/python/tests/servicerunner.py 2012-10-23 15:04:45 +0000
@@ -9,6 +9,7 @@
'stringtests',
'typetests',
'attachmenttests',
+ 'jsonrpc10',
'collectiontest'
]
=== added file 'frameworks/python/tests/services/jsonrpc10.py'
--- frameworks/python/tests/services/jsonrpc10.py 1970-01-01 00:00:00 +0000
+++ frameworks/python/tests/services/jsonrpc10.py 2012-10-23 15:04:45 +0000
@@ -0,0 +1,54 @@
+from ladon.ladonizer import ladonize
+from ladon.compat import PORTABLE_BYTES,PORTABLE_STRING
+import binascii
+import sys
+
+class JsonPrc10Service(object):
+ @ladonize(rtype=PORTABLE_STRING)
+ def return_string(self):
+ if sys.version_info[0]>=3:
+ return 'Yo!!!'
+ return PORTABLE_STRING('Yo!!!','utf-8')
+
+ @ladonize(rtype=int)
+ def return_int(self):
+ return 11
+
+ @ladonize(rtype=float)
+ def return_float(self):
+ return 11.11
+
+ @ladonize(rtype=bool)
+ def return_bool(self):
+ return True
+
+ @ladonize(rtype=PORTABLE_BYTES)
+ def return_bytes(self):
+ if sys.version_info[0]>=3:
+ return PORTABLE_BYTES('Yo!!!','utf-8')
+ return 'Yo!!!'
+
+ @ladonize(PORTABLE_STRING, rtype=PORTABLE_STRING)
+ def passback_string(self,arg):
+ return arg
+
+ @ladonize(int,rtype=int)
+ def passback_int(self,arg):
+ return arg
+
+ @ladonize(float,rtype=float)
+ def passback_float(self,arg):
+ return arg
+
+ @ladonize(bool,rtype=bool)
+ def passback_bool(self,arg):
+ return arg
+
+ @ladonize(PORTABLE_BYTES,rtype=PORTABLE_BYTES)
+ def passback_bytes(self,arg):
+ return arg
+
+ @ladonize(int,float,PORTABLE_STRING,rtype=bool)
+ def params(self,arg0,arg1,arg2):
+ return True
+
\ No newline at end of file
=== added file 'frameworks/python/tests/testjsonrpc10.py'
--- frameworks/python/tests/testjsonrpc10.py 1970-01-01 00:00:00 +0000
+++ frameworks/python/tests/testjsonrpc10.py 2012-10-23 15:04:45 +0000
@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+
+import unittest
+import servicerunner
+import sys
+import xml.dom.minidom as md
+if sys.version_info[0]>=3:
+ from urllib.parse import urlparse,splitport
+ from http.client import HTTPConnection, HTTPSConnection
+else:
+ from urllib import splitport
+ from urlparse import urlparse
+ from httplib import HTTPConnection, HTTPSConnection
+import sys,json
+from ladon.compat import PORTABLE_BYTES,PORTABLE_STRING,PORTABLE_STRING_TYPES
+from testladon import HTTPRequestPoster
+from testladon import str_to_portable_string
+import binascii
+
+class JsonRpc10Tests(unittest.TestCase):
+
+ def setUp(self):
+ self.post_helper = HTTPRequestPoster('http://localhost:2376/JsonPrc10Service')
+
+ def test_get_string(self):
+ req = {'method':'return_string','params':None,'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = str_to_portable_string('Yo!!!')
+ self.assertEqual(res['result'], expected_result)
+
+ def test_get_int(self):
+ req = {'method':'return_int','params':None,'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = 11
+ self.assertEqual(res['result'], expected_result)
+
+ def test_get_float(self):
+ req = {'method':'return_float','params':None,'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = 11.11
+ self.assertEqual(res['result'], expected_result)
+
+ def test_get_bool(self):
+ req = {'method':'return_bool','params':None,'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = True
+ self.assertEqual(res['result'], expected_result)
+
+ def test_get_bytes(self):
+ req = {'method':'return_bytes','params':None,'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = 'Yo!!!'
+ self.assertEqual(res['result'], expected_result)
+
+ def test_passback_string(self):
+ val = 'Yo!!!'
+ req = {'method':'passback_string','params':{'arg':val},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = str_to_portable_string(val)
+ self.assertEqual(res['result'], expected_result)
+
+ def test_passback_int(self):
+ val = 11
+ req = {'method':'passback_int','params':{'arg':val},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = val
+ self.assertEqual(res['result'], expected_result)
+
+ def test_passback_float(self):
+ val = 11.11
+ req = {'method':'passback_float','params':{'arg':val},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = val
+ self.assertEqual(res['result'], expected_result)
+
+ def test_passback_bool(self):
+ val = True
+ req = {'method':'passback_bool','params':{'arg':val},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ expected_result = val
+ self.assertEqual(res['result'], expected_result)
+
+ def test_passback_bytes(self):
+ val = 'Yo!!!'
+ req = {'method':'passback_bytes','params':{'arg':val},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ self.assertEqual(res['result'], val)
+
+ def test_validate_request_response_structure(self):
+ req = {}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+
+ self.assertIs(type(res['error']), dict)
+ self.assertTrue('id' is not res)
+ self.assertIs(res['result'], None)
+ self.assertTrue('"method"' in res['error']['string'])
+
+ req = {'method':'passback_string'}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ self.assertIs(type(res['error']), dict)
+ self.assertTrue('id' is not res)
+ self.assertIs(res['result'], None)
+ self.assertTrue('"params"' in res['error']['string'])
+
+ req = {'method':'passback_string','params':None}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+ self.assertIs(type(res['error']), dict)
+ self.assertTrue('id' is not res)
+ self.assertIs(res['result'], None)
+ self.assertTrue('"id"' in res['error']['string'])
+
+ req = {'method':'passback_string','params':None,'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+
+ self.assertIs(type(res['error']), dict)
+ self.assertEqual(res['id'], '0')
+ self.assertIs(res['result'], None)
+
+ req = {'method':'passback_string','params':None,'id':'0'}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+
+ self.assertIs(type(res['error']), dict)
+ self.assertEqual(res['id'], '0')
+ self.assertIs(res['result'], None)
+
+ req = {'method':'passback_string','params':{'arg': 'Yo!!!'},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+
+ self.assertIs(res['error'], None)
+ self.assertEqual(res['id'], '0')
+ self.assertEqual(res['result'], 'Yo!!!')
+
+ req = {'method':'params','params':{},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+
+ self.assertIs(type(res['error']), dict)
+ self.assertEqual(res['id'], '0')
+ self.assertTrue('"arg0"' in res['error']['string'])
+
+ req = {'method':'params','params':{'arg0':11},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+
+ self.assertIs(type(res['error']), dict)
+ self.assertEqual(res['id'], '0')
+ self.assertTrue('"arg1"' in res['error']['string'])
+
+ req = {'method':'params','params':{'arg0':11, 'arg1':11.11},'id':0}
+ jreq = json.dumps(req)
+
+ status,reason,resdata = self.post_helper.post_request(jreq.encode('utf-8'),extra_path='jsonrpc10',encoding='utf-8')
+
+ self.assertEqual(status, 200)
+ res = json.loads(PORTABLE_STRING(resdata,'utf-8'))
+
+ self.assertIs(type(res['error']), dict)
+ self.assertEqual(res['id'], '0')
+ self.assertTrue('"arg2"' in res['error']['string'])
+
+if __name__ == '__main__':
+ import servicerunner
+ servicerunner
+ service_thread = servicerunner.serve_test_service(as_thread=True)
+ unittest.main(exit=False)
+ service_thread.server.shutdown()
\ No newline at end of file
Follow ups