Correcting the types of the values in the returned data
Partially implements: blueprint test-with-xml Change-Id: I6db4ac284b224c994ec6b674cfb8cb053e4b2734
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user