Files
deb-ryu/ryu/tests/unit/lib/test_rpc.py
IWASE Yusuke 2ae4f884ab tox: Adapt to PyPy interpreter
Note: Though tests may not be enough, as far as running unit test,
this patch makes compatible with PyPy interpreter.

Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
2016-02-10 13:46:35 +09:00

388 lines
12 KiB
Python

# Copyright (C) 2013-2015 Nippon Telegraph and Telephone Corporation.
# Copyright (C) 2013-2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numbers
import time
import sys
if sys.version_info < (2, 7):
import unittest2 as unittest
else:
import unittest
from nose.tools import raises
import six
from ryu.lib import hub
hub.patch()
from ryu.lib import rpc
class MyException(BaseException):
pass
class Test_rpc(unittest.TestCase):
""" Test case for ryu.lib.rpc
"""
def _handle_request(self, m):
e = self._server_endpoint
msgid, method, params = m
if method == b'resp':
e.send_response(msgid, result=params[0])
elif method == b'err':
e.send_response(msgid, error=params[0])
elif method == b'callback':
n, cb, v = params
assert n > 0
self._requests.add(e.send_request(cb, [msgid, n, cb, v]))
elif method == b'notify1':
e.send_notification(params[1], params[2])
e.send_response(msgid, result=params[0])
elif method == b'shutdown':
import socket
# Though six.text_type is not needed in python2, it is
# unconditionally applied for code simplicityp
how = getattr(socket, six.text_type(params[0], 'utf-8'))
self._server_sock.shutdown(how)
e.send_response(msgid, result=method)
else:
raise Exception("unknown method %s" % method)
def _handle_notification(self, m):
e = self._server_endpoint
method, params = m
if method == b'notify2':
e.send_notification(params[0], params[1])
def _handle_response(self, m):
e = self._server_endpoint
msgid, error, result = m
assert error is None
self._requests.remove(msgid)
omsgid, n, cb, v = result
assert n >= 0
if n == 0:
e.send_response(omsgid, result=v)
else:
self._requests.add(e.send_request(cb, [omsgid, n, cb, v]))
def setUp(self):
import socket
self._server_sock, self._client_sock = socket.socketpair()
table = {
rpc.MessageType.REQUEST: self._handle_request,
rpc.MessageType.RESPONSE: self._handle_response,
rpc.MessageType.NOTIFY: self._handle_notification
}
self._requests = set()
self._server_sock.setblocking(0)
self._server_endpoint = rpc.EndPoint(self._server_sock,
disp_table=table)
self._server_thread = hub.spawn(self._server_endpoint.serve)
def tearDown(self):
hub.kill(self._server_thread)
hub.joinall([self._server_thread])
def test_0_call_str(self):
c = rpc.Client(self._client_sock)
obj = b'hoge'
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, bytes)
def test_0_call_int(self):
c = rpc.Client(self._client_sock)
obj = 12345
assert isinstance(obj, int)
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, type(obj))
def test_0_call_int2(self):
c = rpc.Client(self._client_sock)
obj = six.MAXSIZE
assert isinstance(obj, int)
result = c.call(b'resp', [obj])
assert result == obj
import sys
# note: on PyPy, result will be a long type value.
sv = getattr(sys, 'subversion', None)
if sv is not None and sv[0] == 'PyPy':
assert isinstance(result, long)
else:
assert isinstance(result, type(obj))
def test_0_call_int3(self):
c = rpc.Client(self._client_sock)
obj = - six.MAXSIZE - 1
assert isinstance(obj, int)
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, type(obj))
def test_0_call_long(self):
c = rpc.Client(self._client_sock)
obj = 0xffffffffffffffff # max value for msgpack
_long = int if six.PY3 else long
assert isinstance(obj, _long)
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, type(obj))
def test_0_call_long2(self):
c = rpc.Client(self._client_sock)
# NOTE: the python type of this value is int for 64-bit arch
obj = -0x8000000000000000 # min value for msgpack
assert isinstance(obj, numbers.Integral)
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, type(obj))
@raises(TypeError)
def test_0_call_bytearray(self):
c = rpc.Client(self._client_sock)
obj = bytearray(b'foo')
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, bytes)
def test_1_shutdown_wr(self):
# test if the server shutdown on disconnect
import socket
self._client_sock.shutdown(socket.SHUT_WR)
hub.joinall([self._server_thread])
@raises(EOFError)
def test_1_client_shutdown_wr(self):
c = rpc.Client(self._client_sock)
c.call(b'shutdown', [b'SHUT_WR'])
def test_1_call_True(self):
c = rpc.Client(self._client_sock)
obj = True
assert c.call(b'resp', [obj]) == obj
def test_2_call_None(self):
c = rpc.Client(self._client_sock)
obj = None
assert c.call(b'resp', [obj]) is None
def test_2_call_False(self):
c = rpc.Client(self._client_sock)
obj = False
assert c.call(b'resp', [obj]) == obj
def test_2_call_dict(self):
c = rpc.Client(self._client_sock)
obj = {b'hoge': 1, b'fuga': 2}
assert c.call(b'resp', [obj]) == obj
def test_2_call_empty_dict(self):
c = rpc.Client(self._client_sock)
obj = {}
assert c.call(b'resp', [obj]) == obj
def test_2_call_array(self):
c = rpc.Client(self._client_sock)
obj = [1, 2, 3, 4]
assert c.call(b'resp', [obj]) == obj
def test_2_call_empty_array(self):
c = rpc.Client(self._client_sock)
obj = []
assert c.call(b'resp', [obj]) == obj
def test_2_call_tuple(self):
c = rpc.Client(self._client_sock)
# note: msgpack library implicitly convert a tuple into a list
obj = (1, 2, 3)
assert c.call(b'resp', [obj]) == list(obj)
@raises(TypeError)
def test_2_call_unicode(self):
c = rpc.Client(self._client_sock)
# note: on-wire msgpack has no notion of encoding.
# the msgpack library implicitly converts unicode to
# utf-8 encoded bytes by default.
# we don't want to rely on the behaviour though because
# it seems to be going to change.
# https://gist.github.com/methane/5022403
obj = u"hoge"
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, bytes)
def test_2_call_small_binary(self):
import struct
c = rpc.Client(self._client_sock)
obj = struct.pack("100x")
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, bytes)
def test_3_call_complex(self):
c = rpc.Client(self._client_sock)
obj = [1, b'hoge', {b'foo': 1, 3: b'bar'}]
assert c.call(b'resp', [obj]) == list(obj)
@unittest.skip("doesn't work with eventlet 0.18 and later")
def test_4_call_large_binary(self):
import struct
import sys
# note: on PyPy, this test case may hang up.
sv = getattr(sys, 'subversion', None)
if sv is not None and sv[0] == 'PyPy':
return
c = rpc.Client(self._client_sock)
obj = struct.pack("10000000x")
result = c.call(b'resp', [obj])
assert result == obj
assert isinstance(result, bytes)
def test_0_notification1(self):
l = []
def callback(n):
l.append(n)
c = rpc.Client(self._client_sock, notification_callback=callback)
obj = b'hogehoge'
robj = b'fugafuga'
assert c.call(b'notify1', [robj, b'notify_hoge', [obj]]) == robj
c.receive_notification()
assert len(l) == 1
n = l.pop(0)
assert n is not None
method, params = n
assert method == b'notify_hoge'
assert params[0] == obj
def test_0_notification2(self):
l = []
def callback(n):
l.append(n)
c = rpc.Client(self._client_sock, notification_callback=callback)
obj = b'hogehogehoge'
c.send_notification(b'notify2', [b'notify_hoge', [obj]])
c.receive_notification()
assert len(l) == 1
n = l.pop(0)
assert n is not None
method, params = n
assert method == b'notify_hoge'
assert params[0] == obj
def test_0_call_error(self):
c = rpc.Client(self._client_sock)
obj = b'hoge'
try:
c.call(b'err', [obj])
raise Exception("unexpected")
except rpc.RPCError as e:
assert e.get_value() == obj
def test_0_call_error_notification(self):
l = []
def callback(n):
l.append(n)
c = rpc.Client(self._client_sock, notification_callback=callback)
c.send_notification(b'notify2', [b'notify_foo', []])
hub.sleep(0.5) # give the peer a chance to run
obj = b'hoge'
try:
c.call(b'err', [obj])
raise Exception("unexpected")
except rpc.RPCError as e:
assert e.get_value() == obj
assert len(l) == 1
n = l.pop(0)
method, params = n
assert method == b'notify_foo'
assert params == []
def test_4_async_call(self):
"""send a bunch of requests and then wait for responses
"""
num_calls = 9999
old_blocking = self._client_sock.setblocking(0)
try:
e = rpc.EndPoint(self._client_sock)
s = set()
for i in range(1, num_calls + 1):
s.add(e.send_request(b'resp', [i]))
sum = 0
while s:
e.block()
e.process()
done = set()
for x in s:
r = e.get_response(x)
if r is None:
continue
res, error = r
assert error is None
sum += res
done.add(x)
assert done.issubset(s)
s -= done
assert sum == (1 + num_calls) * num_calls / 2
finally:
self._client_sock.setblocking(old_blocking)
def test_4_async_call2(self):
"""both sides act as rpc client and server
"""
assert not self._requests
num_calls = 100
old_blocking = self._client_sock.setblocking(0)
try:
e = rpc.EndPoint(self._client_sock)
s = set()
for i in range(1, num_calls + 1):
s.add(e.send_request(b'callback', [i, b'ourcallback', 0]))
sum = 0
while s:
e.block()
e.process()
done = set()
for x in s:
r = e.get_response(x)
if r is None:
continue
res, error = r
assert error is None
sum += res
done.add(x)
assert done.issubset(s)
s -= done
r = e.get_request()
if r is not None:
msgid, method, params = r
assert method == b'ourcallback'
omsgid, n, cb, v = params
assert omsgid in s
assert cb == b'ourcallback'
assert n > 0
e.send_response(msgid, result=[omsgid, n - 1, cb, v + 1])
assert sum == (1 + num_calls) * num_calls / 2
finally:
self._client_sock.setblocking(old_blocking)
assert not self._requests