Revision d357f531

b/lib/serializer.py
36 36
except ImportError:
37 37
  import sha as sha1
38 38

  
39
# Check whether the simplejson module supports indentation
39

  
40 40
_JSON_INDENT = 2
41
try:
42
  simplejson.dumps(1, indent=_JSON_INDENT)
43
except TypeError:
44
  _JSON_INDENT = None
45 41

  
46 42
_RE_EOLSP = re.compile('[ \t]+$', re.MULTILINE)
47 43

  
48 44

  
45
def _GetJsonDumpers():
46
  """Returns two JSON functions to serialize data.
47

  
48
  @rtype: (callable, callable)
49
  @return: The function to generate a compact form of JSON and another one to
50
           generate a more readable, indented form of JSON (if supported)
51

  
52
  """
53
  plain_dump = simplejson.dumps
54

  
55
  # Check whether the simplejson module supports indentation
56
  try:
57
    simplejson.dumps(1, indent=_JSON_INDENT)
58
  except TypeError:
59
    # Indentation not supported
60
    indent_dump = plain_dump
61
  else:
62
    # Indentation supported
63
    indent_dump = lambda data: simplejson.dumps(data, indent=_JSON_INDENT)
64

  
65
  assert callable(plain_dump)
66
  assert callable(indent_dump)
67

  
68
  return (plain_dump, indent_dump)
69

  
70

  
71
(_DumpJson, _DumpJsonIndent) = _GetJsonDumpers()
72

  
73

  
49 74
def DumpJson(data, indent=True):
50 75
  """Serialize a given object.
51 76

  
......
55 80
  @return: the string representation of data
56 81

  
57 82
  """
58
  if not indent or _JSON_INDENT is None:
59
    txt = simplejson.dumps(data)
83
  if indent:
84
    fn = _DumpJsonIndent
60 85
  else:
61
    txt = simplejson.dumps(data, indent=_JSON_INDENT, sort_keys=True)
86
    fn = _DumpJson
62 87

  
63
  txt = _RE_EOLSP.sub("", txt)
88
  txt = _RE_EOLSP.sub("", fn(data))
64 89
  if not txt.endswith('\n'):
65 90
    txt += '\n'
91

  
66 92
  return txt
67 93

  
68 94

  
b/test/ganeti.serializer_unittest.py
27 27
from ganeti import serializer
28 28
from ganeti import errors
29 29

  
30
import testutils
30 31

  
31
class SimplejsonMock(object):
32
  def dumps(self, data, indent=None):
33
    return repr(data)
34 32

  
35
  def loads(self, data):
36
    return eval(data)
37

  
38

  
39
class TestSerializer(unittest.TestCase):
33
class TestSerializer(testutils.GanetiTestCase):
40 34
  """Serializer tests"""
41 35

  
42 36
  _TESTDATA = [
......
44 38
    255,
45 39
    [1, 2, 3],
46 40
    (1, 2, 3),
47
    { 1: 2, "foo": "bar", },
41
    { "1": 2, "foo": "bar", },
42
    ["abc", 1, 2, 3, 999,
43
      {
44
        "a1": ("Hello", "World"),
45
        "a2": "This is only a test",
46
        "a3": None,
47
        },
48
      {
49
        "foo": "bar",
50
        },
51
      ]
48 52
    ]
49 53

  
50
  def setUp(self):
51
    self._orig_simplejson = serializer.simplejson
52
    serializer.simplejson = SimplejsonMock()
53

  
54
  def tearDown(self):
55
    serializer.simplejson = self._orig_simplejson
54
  def _TestSerializer(self, dump_fn, load_fn):
55
    for data in self._TESTDATA:
56
      self.failUnless(dump_fn(data).endswith("\n"))
57
      self.assertEqualValues(load_fn(dump_fn(data)), data)
56 58

  
57 59
  def testGeneric(self):
58 60
    return self._TestSerializer(serializer.Dump, serializer.Load)
......
65 67
    DumpSigned = serializer.DumpSigned
66 68

  
67 69
    for data in self._TESTDATA:
68
      self.assertEqual(LoadSigned(DumpSigned(data, "mykey"), "mykey"),
69
                       (data, ''))
70
      self.assertEqual(LoadSigned(
71
                         DumpSigned(data, "myprivatekey", "mysalt"),
72
                         "myprivatekey"), (data, "mysalt"))
70
      self.assertEqualValues(LoadSigned(DumpSigned(data, "mykey"), "mykey"),
71
                             (data, ''))
72
      self.assertEqualValues(LoadSigned(DumpSigned(data, "myprivatekey",
73
                                                   "mysalt"),
74
                                        "myprivatekey"),
75
                             (data, "mysalt"))
76

  
73 77
    self.assertRaises(errors.SignatureError, serializer.LoadSigned,
74 78
                      serializer.DumpSigned("test", "myprivatekey"),
75 79
                      "myotherkey")
76 80

  
77
  def _TestSerializer(self, dump_fn, load_fn):
78
    for data in self._TESTDATA:
79
      self.failUnless(dump_fn(data).endswith("\n"))
80
      self.failUnlessEqual(load_fn(dump_fn(data)), data)
81

  
82 81

  
83 82
if __name__ == '__main__':
84 83
  unittest.main()
b/test/testutils.py
75 75
    actual_mode = stat.S_IMODE(st.st_mode)
76 76
    self.assertEqual(actual_mode, expected_mode)
77 77

  
78
  def assertEqualValues(self, first, second, msg=None):
79
    """Compares two values whether they're equal.
80

  
81
    Tuples are automatically converted to lists before comparing.
82

  
83
    """
84
    return self.assertEqual(UnifyValueType(first),
85
                            UnifyValueType(second),
86
                            msg=msg)
87

  
78 88
  @staticmethod
79 89
  def _TestDataFilename(name):
80 90
    """Returns the filename of a given test data file.
......
97 107
    proper test file name.
98 108

  
99 109
    """
100

  
101 110
    return utils.ReadFile(cls._TestDataFilename(name))
102 111

  
103 112
  def _CreateTempFile(self):
......
111 120
    os.close(fh)
112 121
    self._temp_files.append(fname)
113 122
    return fname
123

  
124

  
125
def UnifyValueType(data):
126
  """Converts all tuples into lists.
127

  
128
  This is useful for unittests where an external library doesn't keep types.
129

  
130
  """
131
  if isinstance(data, (tuple, list)):
132
    return [UnifyValueType(i) for i in data]
133

  
134
  elif isinstance(data, dict):
135
    return dict([(UnifyValueType(key), UnifyValueType(value))
136
                 for (key, value) in data.iteritems()])
137

  
138
  return data

Also available in: Unified diff