Correcting the types of the values in the returned data

Partially implements: blueprint test-with-xml
Change-Id: I6db4ac284b224c994ec6b674cfb8cb053e4b2734
This commit is contained in:
DJ Johnstone
2013-01-23 11:52:36 -06:00
parent 28c8f2aa20
commit 5925e50c8c
2 changed files with 124 additions and 8 deletions

View File

@@ -5,23 +5,52 @@ from numbers import Number
from reddwarfclient import exceptions
from reddwarfclient.client import ReddwarfHTTPClient
XML_NS = {None: "http://docs.openstack.org/database/api/v1.0"}
# This dictionary contains XML paths of things that should become list items.
# If XML element is listed here then this searches through the ancestors.
LISTIFY = {
"accounts": [[]],
"databases": [[]],
"flavors": [[]],
"instances": [[]],
"links": [["flavor", "instance", "instances"],
["instance", "instances"]],
"links": [[]],
"hosts": [[]],
"devices": [[]],
"users": [[]],
"versions": [[]],
"attachments": [[]]
}
TYPE_MAP = {
"instance": {
"volume": {
"used": float,
"size": int,
},
"deleted": bool,
"server": {
"local_id": int,
"deleted": bool,
},
},
"instances": {
"deleted": bool,
},
"deleted": bool,
"flavor": {
"ram": int,
},
"diagnostics": {
"vmHwm": int,
"vmPeak": int,
"vmSize": int,
"threads": int,
"vmRss": int,
"fdSize": int,
},
}
TYPE_MAP["flavors"] = TYPE_MAP["flavor"]
REQUEST_AS_LIST = set(['databases', 'users'])
@@ -60,8 +89,11 @@ def element_to_json(name, element):
def root_element_to_json(name, element):
"""Returns a tuple of the root JSON value, plus the links if found."""
if name == "rootEnabled": # Why oh why were we inconsistent here? :'(
return bool(element.text), None
elif element_must_be_list(element, name):
if element.text.strip() == "False":
return False, None
elif element.text.strip() == "True":
return True, None
if element_must_be_list(element, name):
return element_to_list(element, True)
else:
return element_to_dict(element), None
@@ -93,6 +125,12 @@ def element_to_dict(element):
for child_element in element:
name = normalize_tag(child_element)
result[name] = element_to_json(name, child_element)
if len(result) == 0 and element.text:
string_value = element.text.strip()
if len(string_value):
if string_value == 'None':
return None
return string_value
return result
@@ -177,10 +215,36 @@ def populate_element_from_dict(element, dict):
element.set(key, value)
elif isinstance(value, Number):
element.set(key, str(value))
elif isinstance(value, None.__class__):
element.set(key, '')
else:
create_subelement(element, key, value)
def modify_response_types(value, type_translator):
"""
This will convert some string in response dictionary to ints or bool
so that our respose is compatiable with code expecting JSON style responses
"""
if isinstance(value, str):
if value == 'True':
return True
elif value == 'False':
return False
else:
return type_translator(value)
elif isinstance(value, dict):
for k, v in value.iteritems():
if v.__class__ is dict and v.__len__() == 0:
value[k] = None
if k in type_translator:
value[k] = modify_response_types(value[k], type_translator[k])
return value
elif isinstance(value, list):
return [modify_response_types(element, type_translator)
for element in value]
class ReddwarfXmlClient(ReddwarfHTTPClient):
@classmethod
@@ -208,4 +272,5 @@ class ReddwarfXmlClient(ReddwarfHTTPClient):
result = {root_name: root_value}
if links:
result['links'] = links
modify_response_types(result, TYPE_MAP)
return result

View File

@@ -37,6 +37,20 @@ class XmlTest(TestCase):
['instances',
'instance']))
def test_populate_element_from_dict(self):
# Test populate_element_from_dict with a None in the data
ele = '''
<instance>
<volume>
<value size="5"/>
</volume>
</instance>
'''
rt = etree.fromstring(ele)
self.assertEqual(None, xml.populate_element_from_dict(rt,
{'size': None}))
def test_element_must_be_list(self):
# Test for when name isn't in the dictionary
self.assertFalse(xml.element_must_be_list(self.ROOT, "not_in_list"))
@@ -66,9 +80,15 @@ class XmlTest(TestCase):
self.assertEqual((exp, None),
xml.root_element_to_json("not_in_list", self.ROOT))
# Test rootEnabled:
# Test rootEnabled True:
t_element = etree.fromstring('''<rootEnabled> True </rootEnabled>''')
self.assertEqual((True, None),
xml.root_element_to_json("rootEnabled", self.ROOT))
xml.root_element_to_json("rootEnabled", t_element))
# Test rootEnabled False:
f_element = etree.fromstring('''<rootEnabled> False </rootEnabled>''')
self.assertEqual((False, None),
xml.root_element_to_json("rootEnabled", f_element))
def test_element_to_list(self):
# Test w/ no child elements
@@ -89,9 +109,19 @@ class XmlTest(TestCase):
check_for_links=True))
def test_element_to_dict(self):
# Test when there is not a None
exp = {'instance': {'flavor': {'links': [], 'value': {'value': '5'}}}}
self.assertEqual(exp, xml.element_to_dict(self.ROOT))
# Test when there is a None
element = '''
<server>
None
</server>
'''
rt = etree.fromstring(element)
self.assertEqual(None, xml.element_to_dict(rt))
def test_standarize_json(self):
xml.standardize_json_lists(self.JSON)
self.assertEqual({'instances': ['1', '2', '3'],
@@ -154,6 +184,27 @@ class XmlTest(TestCase):
except TypeError:
pass
def test_modify_response_types(self):
TYPE_MAP = {
"Int": int,
"Bool": bool
}
#Is a string True
self.assertEqual(True, xml.modify_response_types('True', TYPE_MAP))
#Is a string False
self.assertEqual(False, xml.modify_response_types('False', TYPE_MAP))
#Is a dict
test_dict = {"Int": "5"}
test_dict = xml.modify_response_types(test_dict, TYPE_MAP)
self.assertEqual(int, test_dict["Int"].__class__)
#Is a list
test_list = {"a_list": [{"Int": "5"}, {"Str": "A"}]}
test_list = xml.modify_response_types(test_list["a_list"], TYPE_MAP)
self.assertEqual([{'Int': 5}, {'Str': 'A'}], test_list)
def test_reddwarfxmlclient(self):
from reddwarfclient import exceptions