summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ryu/lib/rpc.py20
-rw-r--r--ryu/services/protocols/bgp/net_ctrl.py8
-rw-r--r--ryu/tests/unit/lib/test_rpc.py148
3 files changed, 77 insertions, 99 deletions
diff --git a/ryu/lib/rpc.py b/ryu/lib/rpc.py
index ed38f976..bb4742a0 100644
--- a/ryu/lib/rpc.py
+++ b/ryu/lib/rpc.py
@@ -14,8 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# msgpack-rpc
-# http://wiki.msgpack.org/display/MSGPACK/RPC+specification
+# Specification:
+# - msgpack
+# https://github.com/msgpack/msgpack/blob/master/spec.md
+# - msgpack-rpc
+# https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md
from collections import deque
import select
@@ -36,13 +39,8 @@ class MessageEncoder(object):
"""
def __init__(self):
super(MessageEncoder, self).__init__()
- # note: on-wire msgpack has no notion of encoding.
- # the msgpack-python 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.
- # cf. https://gist.github.com/methane/5022403
- self._packer = msgpack.Packer(encoding=None)
- self._unpacker = msgpack.Unpacker(encoding=None)
+ self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True)
+ self._unpacker = msgpack.Unpacker(encoding='utf-8')
self._next_msgid = 0
def _create_msgid(self):
@@ -51,7 +49,7 @@ class MessageEncoder(object):
return this_id
def create_request(self, method, params):
- assert isinstance(method, six.binary_type)
+ assert isinstance(method, (str, six.binary_type))
assert isinstance(params, list)
msgid = self._create_msgid()
return (self._packer.pack(
@@ -64,7 +62,7 @@ class MessageEncoder(object):
return self._packer.pack([MessageType.RESPONSE, msgid, error, result])
def create_notification(self, method, params):
- assert isinstance(method, six.binary_type)
+ assert isinstance(method, (str, six.binary_type))
assert isinstance(params, list)
return self._packer.pack([MessageType.NOTIFY, method, params])
diff --git a/ryu/services/protocols/bgp/net_ctrl.py b/ryu/services/protocols/bgp/net_ctrl.py
index 7cb10460..dcd9870b 100644
--- a/ryu/services/protocols/bgp/net_ctrl.py
+++ b/ryu/services/protocols/bgp/net_ctrl.py
@@ -23,6 +23,8 @@ import logging
import socket
import traceback
+import msgpack
+
from ryu.services.protocols.bgp import api
from ryu.services.protocols.bgp.api.base import ApiException
from ryu.services.protocols.bgp.api.base import NEXT_HOP
@@ -95,10 +97,8 @@ class RpcSession(Activity):
def __init__(self, socket, outgoing_msg_sink_iter):
super(RpcSession, self).__init__("RpcSession(%s)" % socket)
- import msgpack
-
- self._packer = msgpack.Packer()
- self._unpacker = msgpack.Unpacker()
+ self._packer = msgpack.Packer(encoding='utf-8')
+ self._unpacker = msgpack.Unpacker(encoding='utf-8')
self._next_msgid = 0
self._socket = socket
self._outgoing_msg_sink_iter = outgoing_msg_sink_iter
diff --git a/ryu/tests/unit/lib/test_rpc.py b/ryu/tests/unit/lib/test_rpc.py
index b0adf208..2df123ee 100644
--- a/ryu/tests/unit/lib/test_rpc.py
+++ b/ryu/tests/unit/lib/test_rpc.py
@@ -15,17 +15,14 @@
# limitations under the License.
import numbers
-import time
-import sys
-if sys.version_info < (2, 7):
- import unittest2 as unittest
-else:
- import unittest
+import socket
+import struct
+import unittest
+
from nose.tools import raises
import six
from ryu.lib import hub
-hub.patch()
from ryu.lib import rpc
@@ -40,22 +37,19 @@ class Test_rpc(unittest.TestCase):
def _handle_request(self, m):
e = self._server_endpoint
msgid, method, params = m
- if method == b'resp':
+ if method == 'resp':
e.send_response(msgid, result=params[0])
- elif method == b'err':
+ elif method == 'err':
e.send_response(msgid, error=params[0])
- elif method == b'callback':
+ elif method == 'callback':
n, cb, v = params
assert n > 0
self._requests.add(e.send_request(cb, [msgid, n, cb, v]))
- elif method == b'notify1':
+ elif method == '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'))
+ elif method == 'shutdown':
+ how = getattr(socket, params[0])
self._server_sock.shutdown(how)
e.send_response(msgid, result=method)
else:
@@ -64,7 +58,7 @@ class Test_rpc(unittest.TestCase):
def _handle_notification(self, m):
e = self._server_endpoint
method, params = m
- if method == b'notify2':
+ if method == 'notify2':
e.send_notification(params[0], params[1])
def _handle_response(self, m):
@@ -80,8 +74,6 @@ class Test_rpc(unittest.TestCase):
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,
@@ -100,24 +92,24 @@ class Test_rpc(unittest.TestCase):
def test_0_call_str(self):
c = rpc.Client(self._client_sock)
- obj = b'hoge'
- result = c.call(b'resp', [obj])
+ obj = 'hoge'
+ result = c.call('resp', [obj])
assert result == obj
- assert isinstance(result, bytes)
+ assert isinstance(result, str)
def test_0_call_int(self):
c = rpc.Client(self._client_sock)
obj = 12345
assert isinstance(obj, int)
- result = c.call(b'resp', [obj])
+ result = c.call('resp', [obj])
assert result == obj
- assert isinstance(result, type(obj))
+ assert isinstance(result, numbers.Integral)
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])
+ result = c.call('resp', [obj])
assert result == obj
assert isinstance(result, numbers.Integral)
@@ -125,7 +117,7 @@ class Test_rpc(unittest.TestCase):
c = rpc.Client(self._client_sock)
obj = - six.MAXSIZE - 1
assert isinstance(obj, int)
- result = c.call(b'resp', [obj])
+ result = c.call('resp', [obj])
assert result == obj
assert isinstance(result, numbers.Integral)
@@ -133,120 +125,108 @@ class Test_rpc(unittest.TestCase):
c = rpc.Client(self._client_sock)
obj = 0xffffffffffffffff # max value for msgpack
assert isinstance(obj, numbers.Integral)
- result = c.call(b'resp', [obj])
+ result = c.call('resp', [obj])
assert result == obj
assert isinstance(result, numbers.Integral)
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
+ # 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])
+ result = c.call('resp', [obj])
assert result == obj
- assert isinstance(result, type(obj))
+ assert isinstance(result, numbers.Integral)
@raises(TypeError)
def test_0_call_bytearray(self):
c = rpc.Client(self._client_sock)
obj = bytearray(b'foo')
- result = c.call(b'resp', [obj])
+ result = c.call('resp', [obj])
assert result == obj
- assert isinstance(result, bytes)
+ assert isinstance(result, str)
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'])
+ c.call('shutdown', ['SHUT_WR'])
def test_1_call_True(self):
c = rpc.Client(self._client_sock)
obj = True
- assert c.call(b'resp', [obj]) == obj
+ assert c.call('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
+ assert c.call('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
+ assert c.call('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
+ obj = {'hoge': 1, 'fuga': 2}
+ assert c.call('resp', [obj]) == obj
def test_2_call_empty_dict(self):
c = rpc.Client(self._client_sock)
obj = {}
- assert c.call(b'resp', [obj]) == obj
+ assert c.call('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
+ assert c.call('resp', [obj]) == obj
def test_2_call_empty_array(self):
c = rpc.Client(self._client_sock)
obj = []
- assert c.call(b'resp', [obj]) == obj
+ assert c.call('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
+ # Note: msgpack library implicitly convert a tuple into a list
obj = (1, 2, 3)
- assert c.call(b'resp', [obj]) == list(obj)
+ assert c.call('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
+ # Note: We use encoding='utf-8' option in msgpack.Packer/Unpacker
+ # in order to support Python 3.
+ # With this option, utf-8 encoded bytes will be decoded into unicode
+ # type in Python 2 and str type in Python 3.
obj = u"hoge"
- result = c.call(b'resp', [obj])
+ result = c.call('resp', [obj])
assert result == obj
- assert isinstance(result, bytes)
+ assert isinstance(result, six.text_type)
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])
+ result = c.call('resp', [obj])
assert result == obj
- assert isinstance(result, bytes)
+ assert isinstance(result, six.binary_type)
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)
+ obj = [1, 'hoge', {'foo': 1, 3: 'bar'}]
+ assert c.call('resp', [obj]) == 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])
+ result = c.call('resp', [obj])
assert result == obj
- assert isinstance(result, bytes)
+ assert isinstance(result, six.binary_type)
def test_0_notification1(self):
l = []
@@ -254,15 +234,15 @@ class Test_rpc(unittest.TestCase):
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
+ obj = 'hogehoge'
+ robj = 'fugafuga'
+ assert c.call('notify1', [robj, '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 method == 'notify_hoge'
assert params[0] == obj
def test_0_notification2(self):
@@ -271,21 +251,21 @@ class Test_rpc(unittest.TestCase):
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]])
+ obj = 'hogehogehoge'
+ c.send_notification('notify2', ['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 method == 'notify_hoge'
assert params[0] == obj
def test_0_call_error(self):
c = rpc.Client(self._client_sock)
- obj = b'hoge'
+ obj = 'hoge'
try:
- c.call(b'err', [obj])
+ c.call('err', [obj])
raise Exception("unexpected")
except rpc.RPCError as e:
assert e.get_value() == obj
@@ -296,18 +276,18 @@ class Test_rpc(unittest.TestCase):
def callback(n):
l.append(n)
c = rpc.Client(self._client_sock, notification_callback=callback)
- c.send_notification(b'notify2', [b'notify_foo', []])
+ c.send_notification('notify2', ['notify_foo', []])
hub.sleep(0.5) # give the peer a chance to run
- obj = b'hoge'
+ obj = 'hoge'
try:
- c.call(b'err', [obj])
+ c.call('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 method == 'notify_foo'
assert params == []
def test_4_async_call(self):
@@ -319,7 +299,7 @@ class Test_rpc(unittest.TestCase):
e = rpc.EndPoint(self._client_sock)
s = set()
for i in range(1, num_calls + 1):
- s.add(e.send_request(b'resp', [i]))
+ s.add(e.send_request('resp', [i]))
sum = 0
while s:
e.block()
@@ -349,7 +329,7 @@ class Test_rpc(unittest.TestCase):
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]))
+ s.add(e.send_request('callback', [i, 'ourcallback', 0]))
sum = 0
while s:
e.block()
@@ -368,10 +348,10 @@ class Test_rpc(unittest.TestCase):
r = e.get_request()
if r is not None:
msgid, method, params = r
- assert method == b'ourcallback'
+ assert method == 'ourcallback'
omsgid, n, cb, v = params
assert omsgid in s
- assert cb == b'ourcallback'
+ assert cb == 'ourcallback'
assert n > 0
e.send_response(msgid, result=[omsgid, n - 1, cb, v + 1])
assert sum == (1 + num_calls) * num_calls / 2