d149e5b8 |
#
# Copyright (c) 2011 Edward Langley
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# Neither the name of the project's author nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
from twisted.trial import unittest
import StringIO
import mock
import jsonrpc.server
import jsonrpc.jsonutil
from twisted.web.test.test_web import DummyRequest
|
cc11cbe4 |
from twisted.internet.defer import succeed, DeferredList
|
d149e5b8 |
from twisted.web.static import server
def _render(resource, request):
result = resource.render(request)
if isinstance(result, str):
request.write(result)
request.finish()
return succeed(None)
elif result is server.NOT_DONE_YET:
if request.finished:
return succeed(None)
else:
return request.notifyFinish()
else:
raise ValueError("Unexpected return value: %r" % (result,))
class SimpleEventHandler(jsonrpc.server.ServerEvents):
def log(self, result, request): pass
def findmethod(self, method):
if method in set(['echo', 'add']):
return getattr(self, method)
def add(self, a,b):
return a+b
def echo(self, v): return v
class TestJSONRPCServer(unittest.TestCase):
def setUp(self):
self.id_ = 'an_id'
self.param = "some data"
|
3ae840e0 |
def test_eventhandler(self):
resource = jsonrpc.server.JSON_RPC()
resource.eventhandler = mock.Mock(jsonrpc.server.ServerEvents)
resource.eventhandler.findmethod.return_value = lambda *a, **b: 'test data'
rv = {"jsonrpc": "2.0", "params": [self.param], "method": "echo", "id": self.id_}
resource.eventhandler.processcontent.return_value = rv
resource.eventhandler.processrequest.return_value = rv
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO(jsonrpc.jsonutil.encode(rv))
d = _render(resource, request)
@d.addCallback
def rendered(ignored):
|
8445cb9a |
self.assertTrue(resource.eventhandler.processcontent.called)
self.assertTrue(resource.eventhandler.callmethod.called)
self.assertTrue(resource.eventhandler.processrequest.called)
self.assertTrue(resource.eventhandler.log.called)
|
3ae840e0 |
return d
|
cc11cbe4 |
def test_requestid(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request0 = DummyRequest([''])
request0.getCookie = mock.Mock()
request0.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_))
d0 = _render(resource, request0)
@d0.addCallback
def rendered(ignored):
self.assertEqual(len(request0.written), 1)
data = jsonrpc.jsonutil.decode(request0.written[0])
self.assertEqual(data["id"], self.id_)
request1 = DummyRequest([''])
request1.getCookie = mock.Mock()
request1.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": 1}' % jsonrpc.jsonutil.encode([self.param]))
d1 = _render(resource, request1)
@d1.addCallback
def rendered(ignored):
self.assertEqual(len(request1.written), 1)
data = jsonrpc.jsonutil.decode(request1.written[0])
self.assertEqual(data["id"], 1)
request3 = DummyRequest([''])
request3.getCookie = mock.Mock()
request3.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": []}' % jsonrpc.jsonutil.encode([self.param]))
d3 = _render(resource, request3)
@d3.addCallback
def rendered(ignored):
self.assertEqual(len(request3.written), 1)
data = jsonrpc.jsonutil.decode(request3.written[0])
self.assertNotEqual(data["id"], [])
request4 = DummyRequest([''])
request4.getCookie = mock.Mock()
request4.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": {}}' % jsonrpc.jsonutil.encode([self.param]))
d4 = _render(resource, request4)
@d4.addCallback
def rendered(ignored):
self.assertEqual(len(request4.written), 1)
data = jsonrpc.jsonutil.decode(request4.written[0])
self.assertNotEqual(data["id"], {})
return DeferredList([d0,d1,d3,d4])
|
3ae840e0 |
|
d149e5b8 |
def test_invalid_data(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO(' {"v": %s}, "method": "echo"}' % (jsonrpc.jsonutil.encode(self.param)))
d = _render(resource, request)
@d.addCallback
def rendered(ignored):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(data, {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error."}, "id": None})
|
d149e5b8 |
return d
def test_wrongversion(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO('{"jsonrpc": "2.1", "params": %s, "method": "echo", "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_))
d = _render(resource, request)
@d.addCallback
def rendered(ignored):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(data, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": self.id_})
|
d149e5b8 |
return d
def test_invalidmethodname(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": 0, "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_))
d = _render(resource, request)
@d.addCallback
def rendered(ignored):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(data, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": self.id_})
|
d149e5b8 |
return d
def test_missingmethod(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "non_existent", "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_))
d = _render(resource, request)
@d.addCallback
def rendered(ignored):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(data, {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Procedure not found."}, "id": self.id_})
|
d149e5b8 |
return d
def test_simplecall(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_))
d = _render(resource, request)
@d.addCallback
def rendered(ignored):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(data['id'], self.id_)
self.assertEqual(data['result'], self.param)
|
d149e5b8 |
return d
def test_notify(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": {"v": %s}, "method": "echo"}' % (jsonrpc.jsonutil.encode(self.param)))
d = _render(resource, request)
@d.addCallback
def rendered(ignored):
|
8445cb9a |
self.assertEqual(len(request.written), 0)
|
d149e5b8 |
return d
def test_kwcall(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": {"v": %s}, "method": "echo", "id": "%s"}' % (jsonrpc.jsonutil.encode(self.param), self.id_))
d = _render(resource, request)
@d.addCallback
def rendered(ignored):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(data['id'], self.id_)
self.assertEqual(data['result'], self.param)
|
d149e5b8 |
return d
def test_err(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.getCookie = mock.Mock()
request.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": [1, "sss"], "method": "add", "id": "%s"}' % self.id_)
d = _render(resource, request)
@d.addCallback
def rendered(ignored, *a):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(data['id'], self.id_)
self.assertTrue(data.get('error', False))
|
d149e5b8 |
return rendered
def test_batchcall(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.content = StringIO.StringIO(
'[{"jsonrpc": "2.0", "params": [1, 2], "method": "add", "id": "1"},'
'{"jsonrpc": "2.0", "params": {"a": 3, "b": 2}, "method": "add", "id": "2"}]'
)
request.getCookie = mock.Mock()
d = _render(resource, request)
@d.addCallback
def rendered(ignored, *a):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(len(data), 2)
self.assertEqual(set(x['id'] for x in data), set("12"))
self.assertEqual(set(x['result'] for x in data), set([3,5]))
|
d149e5b8 |
|
8445cb9a |
self.assertFalse(any(x.get('error', False) for x in data))
|
d149e5b8 |
return rendered
def test_batchcall_1err(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.content = StringIO.StringIO(
'[{"jsonrpc": "2.0", "params": [1, 2], "method": "add", "id": "1"},'
'{"jsonrpc": "2.0", "params": {"a": "3", "b": 2}, "method": "add", "id": "2"}]'
)
request.getCookie = mock.Mock()
d = _render(resource, request)
@d.addCallback
def rendered(ignored, *a):
|
8445cb9a |
self.assertEqual(len(request.written), 1)
|
d149e5b8 |
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(len(data), 2)
self.assertEqual(set(x['id'] for x in data), set("12"))
self.assertEqual(set(x.get('result', False) for x in data), set([3,False]))
|
d149e5b8 |
|
8445cb9a |
self.assertEqual(len(filter(None, [x.get('error') for x in data])), 1)
|
d149e5b8 |
return rendered
def test_batchcall_emptylist(self):
resource = jsonrpc.server.JSON_RPC()
resource.customize(SimpleEventHandler)
request = DummyRequest([''])
request.content = StringIO.StringIO('[]')
request.getCookie = mock.Mock()
d = _render(resource, request)
@d.addCallback
def rendered(ignored, *a):
data = jsonrpc.jsonutil.decode(request.written[0])
|
8445cb9a |
self.assertEqual(data, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": None})
|
d149e5b8 |
return rendered
|