Skip to content
Snippets Groups Projects
Commit d357f531 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

Fix serializer unittests


Commit d22b2999 broke the serializer unittests with certain
versions of simplejson. This patch removes sort_keys again
and implements a slightly more efficient way of detecting
simplejson functionality. The serializer unittests no longer
use a partially broken mock, but rather a function to convert all
tuples to lists before comparing.

Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parent aeb0c953
No related merge requests found
...@@ -36,16 +36,41 @@ try: ...@@ -36,16 +36,41 @@ try:
except ImportError: except ImportError:
import sha as sha1 import sha as sha1
# Check whether the simplejson module supports indentation
_JSON_INDENT = 2 _JSON_INDENT = 2
try:
simplejson.dumps(1, indent=_JSON_INDENT)
except TypeError:
_JSON_INDENT = None
_RE_EOLSP = re.compile('[ \t]+$', re.MULTILINE) _RE_EOLSP = re.compile('[ \t]+$', re.MULTILINE)
def _GetJsonDumpers():
"""Returns two JSON functions to serialize data.
@rtype: (callable, callable)
@return: The function to generate a compact form of JSON and another one to
generate a more readable, indented form of JSON (if supported)
"""
plain_dump = simplejson.dumps
# Check whether the simplejson module supports indentation
try:
simplejson.dumps(1, indent=_JSON_INDENT)
except TypeError:
# Indentation not supported
indent_dump = plain_dump
else:
# Indentation supported
indent_dump = lambda data: simplejson.dumps(data, indent=_JSON_INDENT)
assert callable(plain_dump)
assert callable(indent_dump)
return (plain_dump, indent_dump)
(_DumpJson, _DumpJsonIndent) = _GetJsonDumpers()
def DumpJson(data, indent=True): def DumpJson(data, indent=True):
"""Serialize a given object. """Serialize a given object.
...@@ -55,14 +80,15 @@ def DumpJson(data, indent=True): ...@@ -55,14 +80,15 @@ def DumpJson(data, indent=True):
@return: the string representation of data @return: the string representation of data
""" """
if not indent or _JSON_INDENT is None: if indent:
txt = simplejson.dumps(data) fn = _DumpJsonIndent
else: else:
txt = simplejson.dumps(data, indent=_JSON_INDENT, sort_keys=True) fn = _DumpJson
txt = _RE_EOLSP.sub("", txt) txt = _RE_EOLSP.sub("", fn(data))
if not txt.endswith('\n'): if not txt.endswith('\n'):
txt += '\n' txt += '\n'
return txt return txt
......
...@@ -27,16 +27,10 @@ import unittest ...@@ -27,16 +27,10 @@ import unittest
from ganeti import serializer from ganeti import serializer
from ganeti import errors from ganeti import errors
import testutils
class SimplejsonMock(object):
def dumps(self, data, indent=None):
return repr(data)
def loads(self, data): class TestSerializer(testutils.GanetiTestCase):
return eval(data)
class TestSerializer(unittest.TestCase):
"""Serializer tests""" """Serializer tests"""
_TESTDATA = [ _TESTDATA = [
...@@ -44,15 +38,23 @@ class TestSerializer(unittest.TestCase): ...@@ -44,15 +38,23 @@ class TestSerializer(unittest.TestCase):
255, 255,
[1, 2, 3], [1, 2, 3],
(1, 2, 3), (1, 2, 3),
{ 1: 2, "foo": "bar", }, { "1": 2, "foo": "bar", },
["abc", 1, 2, 3, 999,
{
"a1": ("Hello", "World"),
"a2": "This is only a test",
"a3": None,
},
{
"foo": "bar",
},
]
] ]
def setUp(self): def _TestSerializer(self, dump_fn, load_fn):
self._orig_simplejson = serializer.simplejson for data in self._TESTDATA:
serializer.simplejson = SimplejsonMock() self.failUnless(dump_fn(data).endswith("\n"))
self.assertEqualValues(load_fn(dump_fn(data)), data)
def tearDown(self):
serializer.simplejson = self._orig_simplejson
def testGeneric(self): def testGeneric(self):
return self._TestSerializer(serializer.Dump, serializer.Load) return self._TestSerializer(serializer.Dump, serializer.Load)
...@@ -65,20 +67,17 @@ class TestSerializer(unittest.TestCase): ...@@ -65,20 +67,17 @@ class TestSerializer(unittest.TestCase):
DumpSigned = serializer.DumpSigned DumpSigned = serializer.DumpSigned
for data in self._TESTDATA: for data in self._TESTDATA:
self.assertEqual(LoadSigned(DumpSigned(data, "mykey"), "mykey"), self.assertEqualValues(LoadSigned(DumpSigned(data, "mykey"), "mykey"),
(data, '')) (data, ''))
self.assertEqual(LoadSigned( self.assertEqualValues(LoadSigned(DumpSigned(data, "myprivatekey",
DumpSigned(data, "myprivatekey", "mysalt"), "mysalt"),
"myprivatekey"), (data, "mysalt")) "myprivatekey"),
(data, "mysalt"))
self.assertRaises(errors.SignatureError, serializer.LoadSigned, self.assertRaises(errors.SignatureError, serializer.LoadSigned,
serializer.DumpSigned("test", "myprivatekey"), serializer.DumpSigned("test", "myprivatekey"),
"myotherkey") "myotherkey")
def _TestSerializer(self, dump_fn, load_fn):
for data in self._TESTDATA:
self.failUnless(dump_fn(data).endswith("\n"))
self.failUnlessEqual(load_fn(dump_fn(data)), data)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -75,6 +75,16 @@ class GanetiTestCase(unittest.TestCase): ...@@ -75,6 +75,16 @@ class GanetiTestCase(unittest.TestCase):
actual_mode = stat.S_IMODE(st.st_mode) actual_mode = stat.S_IMODE(st.st_mode)
self.assertEqual(actual_mode, expected_mode) self.assertEqual(actual_mode, expected_mode)
def assertEqualValues(self, first, second, msg=None):
"""Compares two values whether they're equal.
Tuples are automatically converted to lists before comparing.
"""
return self.assertEqual(UnifyValueType(first),
UnifyValueType(second),
msg=msg)
@staticmethod @staticmethod
def _TestDataFilename(name): def _TestDataFilename(name):
"""Returns the filename of a given test data file. """Returns the filename of a given test data file.
...@@ -97,7 +107,6 @@ class GanetiTestCase(unittest.TestCase): ...@@ -97,7 +107,6 @@ class GanetiTestCase(unittest.TestCase):
proper test file name. proper test file name.
""" """
return utils.ReadFile(cls._TestDataFilename(name)) return utils.ReadFile(cls._TestDataFilename(name))
def _CreateTempFile(self): def _CreateTempFile(self):
...@@ -111,3 +120,19 @@ class GanetiTestCase(unittest.TestCase): ...@@ -111,3 +120,19 @@ class GanetiTestCase(unittest.TestCase):
os.close(fh) os.close(fh)
self._temp_files.append(fname) self._temp_files.append(fname)
return fname return fname
def UnifyValueType(data):
"""Converts all tuples into lists.
This is useful for unittests where an external library doesn't keep types.
"""
if isinstance(data, (tuple, list)):
return [UnifyValueType(i) for i in data]
elif isinstance(data, dict):
return dict([(UnifyValueType(key), UnifyValueType(value))
for (key, value) in data.iteritems()])
return data
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment