diff --git a/utils/python-rpc/framework/rpc.py b/utils/python-rpc/framework/rpc.py index 9eac5341601..f476b93bf3d 100644 --- a/utils/python-rpc/framework/rpc.py +++ b/utils/python-rpc/framework/rpc.py @@ -33,32 +33,22 @@ class Response(dict): def __init__(self, d): - for k in d.keys(): - if type(d[k]) == dict: - self[k] = Response(d[k]) - elif type(d[k]) == list: - self[k] = [] - for i in range(len(d[k])): - if type(d[k][i]) == dict: - self[k].append(Response(d[k][i])) - else: - self[k].append(d[k][i]) - else: - self[k] = d[k] + for k, v in d.items(): + self[k] = self._decode(v) + + @staticmethod + def _decode(o): + if isinstance(o, dict): + return Response(o) + elif isinstance(o, list): + return [Response._decode(i) for i in o] + else: + return o def __getattr__(self, key): return self[key] def __setattr__(self, key, value): self[key] = value - def __eq__(self, other): - if type(other) == dict: - return self == Response(other) - if self.keys() != other.keys(): - return False - for k in self.keys(): - if self[k] != other[k]: - return False - return True class JSONRPC(object): def __init__(self, url, username=None, password=None): @@ -73,7 +63,7 @@ def send_request(self, path, inputs, result_field = None): headers={'content-type': 'application/json'}, auth=HTTPDigestAuth(self.username, self.password) if self.username is not None else None) res = res.json() - + assert 'error' not in res, res if result_field: diff --git a/utils/python-rpc/framework/test_rpc.py b/utils/python-rpc/framework/test_rpc.py new file mode 100644 index 00000000000..d995e71f51c --- /dev/null +++ b/utils/python-rpc/framework/test_rpc.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +import functools +import unittest + +from rpc import Response + + +class TestResponse(unittest.TestCase): + def test_init__empty(self): + r = Response({}) + assert isinstance(r, Response) + assert len(r) == 0 + + def test_init__scalar_values(self): + r = Response(dict(k='v', k2='vv')) + assert len(r) == 2 + assert r['k'] == 'v' + assert r['k2'] == 'vv' + + def test_init__response_value(self): + child = Response(dict(ck='cv')) + root = dict(k=child) + r = Response(root) + assert len(r) == 1 + assert isinstance(r['k'], Response) + assert r['k'] == child + assert r['k'] is not child + + def test_init__dict_value(self): + child = dict(ck='cv') + root = dict(k=child) + r = Response(root) + assert len(r) == 1 + assert isinstance(r['k'], Response) + assert r['k'] == Response(child) + assert r['k'] is not child + + def test_init__list_value(self): + value = [1, 2] + r = Response(dict(k=value)) + assert len(r) == 1 + assert r['k'] == value + assert r['k'] is not value + + def test_init__list_value_with_nested_response(self): + nested = dict(ck=[1]) + root = dict(k=[nested]) + r = Response(root) + assert len(r) == 1 + assert r['k'] == [Response(nested)] + assert isinstance(r['k'][0], Response) + + def test_init__list_value_with_nested_list(self): + nested = [1, 2] + root = dict(k=[nested]) + r = Response(root) + assert len(r) == 1 + assert r['k'] == [nested] + + def test_getattr__present(self): + r = Response(dict(k='v')) + assert r.k == 'v' + + def test_getattr__missing(self): + # This should raise an AttributeError to match the python data model. + # However, to maintain backwards compatibility, it raises a KeyError. + r = Response({}) + with self.assertRaises(KeyError): + r.k + + def test_setattr(self): + r = Response({}) + r.k = 'v' + assert r.k == 'v' + assert r['k'] == 'v' + + def test_eq__identity(self): + r = Response({}) + assert r == r + + def test_eq__empty(self): + assert Response({}) == Response({}) + + def test_eq__nonnested_matching(self): + assert Response(dict(k='v')) == Response(dict(k='v')) + + def test_eq__nonnested_size_mismatch(self): + assert Response(dict(k='v')) != Response(dict(k='v', k2='v')) + + def test_eq__nonnested_key_mismatch(self): + assert Response(dict(k='v')) != Response(dict(k2='v')) + + def test_eq__nonnested_value_mismatch(self): + assert Response(dict(k='v')) != Response(dict(k='v2')) + + def test_eq__nested(self): + def data(): + return dict(k='v', c=dict(ck='cv')) + + assert Response(data()) == Response(data()) + + def test_eq__list_nonnested(self): + def data(): + return dict(k=[1, 2]) + + assert Response(data()) == Response(data()) + + def test_eq__list_nested_response(self): + def data(): + return dict(k=[Response(dict(ck=[1]))]) + + assert Response(data()) == Response(data()) + + def test_eq__list_nested_list(self): + def data(): + return dict(k=[[Response(dict(k=1))]]) + + assert Response(data()) == Response(data()) + + def test_eq__dict__empty(self): + assert Response({}) == {} + + def test_eq__dict__nonnested(self): + assert Response(dict(k='v')) == dict(k='v') + + def test_eq__dict__nested(self): + def data(): + return dict(k='v', c=dict(ck='cv')) + + assert Response(data()) == data() + + +if __name__ == '__main__': + unittest.main()