summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-11-13 07:07:19 +0000
committerGerrit Code Review <review@openstack.org>2012-11-13 07:07:19 +0000
commit136fd2f26b7b32e87f8ab9ff88025324e269c926 (patch)
tree17ae1b75b4bd51fb4bbc0f5c0091181ac1294553
parent4262020dd36a77397b0b2b10e27d3874aae755eb (diff)
parent8eea01449e7b43a5729df31df9f3f3ffeb55ec78 (diff)
downloadnova-136fd2f26b7b32e87f8ab9ff88025324e269c926.tar.gz
nova-136fd2f26b7b32e87f8ab9ff88025324e269c926.tar.xz
nova-136fd2f26b7b32e87f8ab9ff88025324e269c926.zip
Merge "Remove custom test assertions."
-rw-r--r--nova/test.py83
-rw-r--r--nova/tests/api/ec2/test_cinder_cloud.py28
-rw-r--r--nova/tests/api/ec2/test_cloud.py9
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_aggregates.py4
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_cloudpipe.py3
-rw-r--r--nova/tests/api/openstack/compute/test_consoles.py5
-rw-r--r--nova/tests/api/openstack/compute/test_extensions.py9
-rw-r--r--nova/tests/api/openstack/compute/test_flavors.py9
-rw-r--r--nova/tests/api/openstack/compute/test_images.py12
-rw-r--r--nova/tests/api/openstack/compute/test_limits.py5
-rw-r--r--nova/tests/api/openstack/compute/test_server_actions.py5
-rw-r--r--nova/tests/api/openstack/compute/test_servers.py46
-rw-r--r--nova/tests/api/openstack/compute/test_versions.py7
-rw-r--r--nova/tests/compute/test_compute.py8
-rw-r--r--nova/tests/image/test_glance.py11
-rw-r--r--nova/tests/matchers.py196
-rw-r--r--nova/tests/network/test_manager.py9
-rw-r--r--nova/tests/scheduler/test_host_manager.py9
-rw-r--r--nova/tests/scheduler/test_least_cost.py5
-rw-r--r--nova/tests/scheduler/test_scheduler.py7
-rw-r--r--nova/tests/test_api.py7
-rw-r--r--nova/tests/test_bdm.py3
-rw-r--r--nova/tests/test_db_api.py18
-rw-r--r--nova/tests/test_libvirt.py23
-rw-r--r--nova/tests/test_matchers.py144
-rw-r--r--nova/tests/test_xenapi.py11
26 files changed, 483 insertions, 193 deletions
diff --git a/nova/test.py b/nova/test.py
index 52f63d64b..73956a35c 100644
--- a/nova/test.py
+++ b/nova/test.py
@@ -141,86 +141,3 @@ class TestCase(testtools.TestCase):
svc.start()
self._services.append(svc)
return svc
-
- # Useful assertions
- def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001):
- """Assert two dicts are equivalent.
-
- This is a 'deep' match in the sense that it handles nested
- dictionaries appropriately.
-
- NOTE:
-
- If you don't care (or don't know) a given value, you can specify
- the string DONTCARE as the value. This will cause that dict-item
- to be skipped.
-
- """
- def raise_assertion(msg):
- d1str = str(d1)
- d2str = str(d2)
- base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s '
- 'd2: %(d2str)s' % locals())
- raise AssertionError(base_msg)
-
- d1keys = set(d1.keys())
- d2keys = set(d2.keys())
- if d1keys != d2keys:
- d1only = d1keys - d2keys
- d2only = d2keys - d1keys
- raise_assertion('Keys in d1 and not d2: %(d1only)s. '
- 'Keys in d2 and not d1: %(d2only)s' % locals())
-
- for key in d1keys:
- d1value = d1[key]
- d2value = d2[key]
- try:
- error = abs(float(d1value) - float(d2value))
- within_tolerance = error <= tolerance
- except (ValueError, TypeError):
- # If both values aren't convertible to float, just ignore
- # ValueError if arg is a str, TypeError if it's something else
- # (like None)
- within_tolerance = False
-
- if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'):
- self.assertDictMatch(d1value, d2value)
- elif 'DONTCARE' in (d1value, d2value):
- continue
- elif approx_equal and within_tolerance:
- continue
- elif d1value != d2value:
- raise_assertion("d1['%(key)s']=%(d1value)s != "
- "d2['%(key)s']=%(d2value)s" % locals())
-
- def assertDictListMatch(self, L1, L2, approx_equal=False, tolerance=0.001):
- """Assert a list of dicts are equivalent."""
- def raise_assertion(msg):
- L1str = str(L1)
- L2str = str(L2)
- base_msg = ('List of dictionaries do not match: %(msg)s '
- 'L1: %(L1str)s L2: %(L2str)s' % locals())
- raise AssertionError(base_msg)
-
- L1count = len(L1)
- L2count = len(L2)
- if L1count != L2count:
- raise_assertion('Length mismatch: len(L1)=%(L1count)d != '
- 'len(L2)=%(L2count)d' % locals())
-
- for d1, d2 in zip(L1, L2):
- self.assertDictMatch(d1, d2, approx_equal=approx_equal,
- tolerance=tolerance)
-
- def assertSubDictMatch(self, sub_dict, super_dict):
- """Assert a sub_dict is subset of super_dict."""
- self.assertEqual(True,
- set(sub_dict.keys()).issubset(set(super_dict.keys())))
- for k, sub_value in sub_dict.items():
- super_value = super_dict[k]
- if isinstance(sub_value, dict):
- self.assertSubDictMatch(sub_value, super_value)
- elif 'DONTCARE' in (sub_value, super_value):
- continue
- else:
- self.assertEqual(sub_value, super_value)
diff --git a/nova/tests/api/ec2/test_cinder_cloud.py b/nova/tests/api/ec2/test_cinder_cloud.py
index a858d6f2e..a9f4f742f 100644
--- a/nova/tests/api/ec2/test_cinder_cloud.py
+++ b/nova/tests/api/ec2/test_cinder_cloud.py
@@ -34,6 +34,7 @@ from nova.openstack.common import rpc
from nova import test
from nova.tests import fake_network
from nova.tests.image import fake
+from nova.tests import matchers
from nova import volume
CONF = config.CONF
@@ -434,18 +435,18 @@ class CinderCloudTestCase(test.TestCase):
result = {}
self.cloud._format_instance_bdm(self.context, inst1['uuid'],
'/dev/sdb1', result)
- self.assertSubDictMatch(
+ self.assertThat(
{'rootDeviceType': self._expected_instance_bdm1['rootDeviceType']},
- result)
+ matchers.IsSubDictOf(result))
self._assertEqualBlockDeviceMapping(
self._expected_block_device_mapping0, result['blockDeviceMapping'])
result = {}
self.cloud._format_instance_bdm(self.context, inst2['uuid'],
'/dev/sdc1', result)
- self.assertSubDictMatch(
+ self.assertThat(
{'rootDeviceType': self._expected_instance_bdm2['rootDeviceType']},
- result)
+ matchers.IsSubDictOf(result))
self._tearDownBlockDeviceMapping(inst1, inst2, volumes)
@@ -465,7 +466,7 @@ class CinderCloudTestCase(test.TestCase):
found = False
for y in result:
if x['deviceName'] == y['deviceName']:
- self.assertSubDictMatch(x, y)
+ self.assertThat(x, matchers.IsSubDictOf(y))
found = True
break
self.assertTrue(found)
@@ -477,24 +478,19 @@ class CinderCloudTestCase(test.TestCase):
(inst1, inst2, volumes) = self._setUpBlockDeviceMapping()
result = self._assertInstance(inst1['id'])
- self.assertSubDictMatch(self._expected_instance_bdm1, result)
+ self.assertThat(
+ self._expected_instance_bdm1,
+ matchers.IsSubDictOf(result))
self._assertEqualBlockDeviceMapping(
self._expected_block_device_mapping0, result['blockDeviceMapping'])
result = self._assertInstance(inst2['id'])
- self.assertSubDictMatch(self._expected_instance_bdm2, result)
+ self.assertThat(
+ self._expected_instance_bdm2,
+ matchers.IsSubDictOf(result))
self._tearDownBlockDeviceMapping(inst1, inst2, volumes)
- def assertDictListUnorderedMatch(self, L1, L2, key):
- self.assertEqual(len(L1), len(L2))
- for d1 in L1:
- self.assertTrue(key in d1)
- for d2 in L2:
- self.assertTrue(key in d2)
- if d1[key] == d2[key]:
- self.assertDictMatch(d1, d2)
-
def _setUpImageSet(self, create_volumes_and_snapshots=False):
mappings1 = [
{'device': '/dev/sda1', 'virtual': 'root'},
diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py
index b378ef98d..dae2ee6e2 100644
--- a/nova/tests/api/ec2/test_cloud.py
+++ b/nova/tests/api/ec2/test_cloud.py
@@ -44,6 +44,7 @@ from nova.openstack.common import rpc
from nova import test
from nova.tests import fake_network
from nova.tests.image import fake
+from nova.tests import matchers
from nova import utils
from nova.virt import fake as fake_virt
from nova import volume
@@ -963,7 +964,7 @@ class CloudTestCase(test.TestCase):
for d2 in L2:
self.assertTrue(key in d2)
if d1[key] == d2[key]:
- self.assertDictMatch(d1, d2)
+ self.assertThat(d1, matchers.DictMatches(d2))
def _setUpImageSet(self, create_volumes_and_snapshots=False):
mappings1 = [
@@ -1283,17 +1284,17 @@ class CloudTestCase(test.TestCase):
'imageType': 'machine',
'description': None}
result = self.cloud._format_image(image)
- self.assertDictMatch(result, expected)
+ self.assertThat(result, matchers.DictMatches(expected))
image['properties']['image_location'] = None
expected['imageLocation'] = 'None (name)'
result = self.cloud._format_image(image)
- self.assertDictMatch(result, expected)
+ self.assertThat(result, matchers.DictMatches(expected))
image['name'] = None
image['properties']['image_location'] = 'location'
expected['imageLocation'] = 'location'
expected['name'] = 'location'
result = self.cloud._format_image(image)
- self.assertDictMatch(result, expected)
+ self.assertThat(result, matchers.DictMatches(expected))
def test_deregister_image(self):
deregister_image = self.cloud.deregister_image
diff --git a/nova/tests/api/openstack/compute/contrib/test_aggregates.py b/nova/tests/api/openstack/compute/contrib/test_aggregates.py
index 4fa68bd7d..a209fdce8 100644
--- a/nova/tests/api/openstack/compute/contrib/test_aggregates.py
+++ b/nova/tests/api/openstack/compute/contrib/test_aggregates.py
@@ -22,6 +22,7 @@ from nova import context
from nova import exception
from nova.openstack.common import log as logging
from nova import test
+from nova.tests import matchers
LOG = logging.getLogger(__name__)
AGGREGATE_LIST = [
@@ -319,7 +320,8 @@ class AggregateTestCase(test.TestCase):
def stub_update_aggregate(context, aggregate, values):
self.assertEqual(context, self.context, "context")
self.assertEqual("1", aggregate, "aggregate")
- self.assertDictMatch(body["set_metadata"]['metadata'], values)
+ self.assertThat(body["set_metadata"]['metadata'],
+ matchers.DictMatches(values))
return AGGREGATE
self.stubs.Set(self.controller.api,
"update_aggregate_metadata",
diff --git a/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py
index 12a6c508d..0be17e47a 100644
--- a/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py
+++ b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py
@@ -25,6 +25,7 @@ from nova.openstack.common import timeutils
from nova import test
from nova.tests.api.openstack import fakes
from nova.tests import fake_network
+from nova.tests import matchers
from nova import utils
CONF = config.CONF
@@ -108,7 +109,7 @@ class CloudpipeTest(test.TestCase):
'state': 'running',
'instance_id': 7777,
'created_at': '1981-10-20T00:00:00Z'}]}
- self.assertDictMatch(res_dict, response)
+ self.assertThat(res_dict, matchers.DictMatches(response))
def test_cloudpipe_create(self):
def launch_vpn_instance(context):
diff --git a/nova/tests/api/openstack/compute/test_consoles.py b/nova/tests/api/openstack/compute/test_consoles.py
index 90bd06e3b..8a701588c 100644
--- a/nova/tests/api/openstack/compute/test_consoles.py
+++ b/nova/tests/api/openstack/compute/test_consoles.py
@@ -30,6 +30,7 @@ from nova import flags
from nova.openstack.common import timeutils
from nova import test
from nova.tests.api.openstack import fakes
+from nova.tests import matchers
from nova import utils
FAKE_UUID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
@@ -165,7 +166,7 @@ class ConsolesControllerTest(test.TestCase):
req = fakes.HTTPRequest.blank(self.url + '/20')
res_dict = self.controller.show(req, self.uuid, '20')
- self.assertDictMatch(res_dict, expected)
+ self.assertThat(res_dict, matchers.DictMatches(expected))
def test_show_console_unknown_console(self):
def fake_get_console(cons_self, context, instance_id, console_id):
@@ -209,7 +210,7 @@ class ConsolesControllerTest(test.TestCase):
req = fakes.HTTPRequest.blank(self.url)
res_dict = self.controller.index(req, self.uuid)
- self.assertDictMatch(res_dict, expected)
+ self.assertThat(res_dict, matchers.DictMatches(expected))
def test_delete_console(self):
def fake_get_console(cons_self, context, instance_id, console_id):
diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py
index a4632f479..f3e65a150 100644
--- a/nova/tests/api/openstack/compute/test_extensions.py
+++ b/nova/tests/api/openstack/compute/test_extensions.py
@@ -30,6 +30,7 @@ from nova import flags
from nova.openstack.common import jsonutils
from nova import test
from nova.tests.api.openstack import fakes
+from nova.tests import matchers
CONF = config.CONF
@@ -348,7 +349,7 @@ class ResourceExtensionTest(ExtensionTestCase):
"code": 400
}
}
- self.assertDictMatch(expected, body)
+ self.assertThat(expected, matchers.DictMatches(body))
def test_non_exist_resource(self):
res_ext = base_extensions.ResourceExtension('tweedles',
@@ -366,7 +367,7 @@ class ResourceExtensionTest(ExtensionTestCase):
"code": 404
}
}
- self.assertDictMatch(expected, body)
+ self.assertThat(expected, matchers.DictMatches(body))
class InvalidExtension(object):
@@ -431,7 +432,7 @@ class ActionExtensionTest(ExtensionTestCase):
"code": 400
}
}
- self.assertDictMatch(expected, body)
+ self.assertThat(expected, matchers.DictMatches(body))
def test_non_exist_action(self):
body = dict(blah=dict(name="test"))
@@ -452,7 +453,7 @@ class ActionExtensionTest(ExtensionTestCase):
"code": 400
}
}
- self.assertDictMatch(expected, body)
+ self.assertThat(expected, matchers.DictMatches(body))
class RequestExtensionTest(ExtensionTestCase):
diff --git a/nova/tests/api/openstack/compute/test_flavors.py b/nova/tests/api/openstack/compute/test_flavors.py
index 6726aa579..0fc748fde 100644
--- a/nova/tests/api/openstack/compute/test_flavors.py
+++ b/nova/tests/api/openstack/compute/test_flavors.py
@@ -29,6 +29,7 @@ from nova import exception
from nova import flags
from nova import test
from nova.tests.api.openstack import fakes
+from nova.tests import matchers
NS = "{http://docs.openstack.org/compute/api/v1.1}"
ATOMNS = "{http://www.w3.org/2005/Atom}"
@@ -215,7 +216,7 @@ class FlavorsTest(test.TestCase):
'rel': 'next'}
]
}
- self.assertDictMatch(flavor, expected)
+ self.assertThat(flavor, matchers.DictMatches(expected))
def test_get_flavor_detail_with_limit(self):
req = fakes.HTTPRequest.blank('/v2/fake/flavors/detail?limit=1')
@@ -247,7 +248,8 @@ class FlavorsTest(test.TestCase):
href_parts = urlparse.urlparse(response_links[0]['href'])
self.assertEqual('/v2/fake/flavors', href_parts.path)
params = urlparse.parse_qs(href_parts.query)
- self.assertDictMatch({'limit': ['1'], 'marker': ['1']}, params)
+ self.assertThat({'limit': ['1'], 'marker': ['1']},
+ matchers.DictMatches(params))
def test_get_flavor_with_limit(self):
req = fakes.HTTPRequest.blank('/v2/fake/flavors?limit=2')
@@ -293,7 +295,8 @@ class FlavorsTest(test.TestCase):
href_parts = urlparse.urlparse(response_links[0]['href'])
self.assertEqual('/v2/fake/flavors', href_parts.path)
params = urlparse.parse_qs(href_parts.query)
- self.assertDictMatch({'limit': ['2'], 'marker': ['2']}, params)
+ self.assertThat({'limit': ['2'], 'marker': ['2']},
+ matchers.DictMatches(params))
def test_get_flavor_list_detail(self):
req = fakes.HTTPRequest.blank('/v2/fake/flavors/detail')
diff --git a/nova/tests/api/openstack/compute/test_images.py b/nova/tests/api/openstack/compute/test_images.py
index 34dc2682d..fe49e6c04 100644
--- a/nova/tests/api/openstack/compute/test_images.py
+++ b/nova/tests/api/openstack/compute/test_images.py
@@ -32,6 +32,7 @@ from nova import exception
from nova import flags
from nova import test
from nova.tests.api.openstack import fakes
+from nova.tests import matchers
from nova import utils
NS = "{http://docs.openstack.org/compute/api/v1.1}"
@@ -108,7 +109,7 @@ class ImagesControllerTest(test.TestCase):
},
}
- self.assertDictMatch(expected_image, actual_image)
+ self.assertThat(actual_image, matchers.DictMatches(expected_image))
def test_get_image_with_custom_prefix(self):
self.flags(osapi_compute_link_prefix='https://zoo.com:42',
@@ -162,7 +163,7 @@ class ImagesControllerTest(test.TestCase):
}],
},
}
- self.assertDictMatch(expected_image, actual_image)
+ self.assertThat(actual_image, matchers.DictMatches(expected_image))
def test_get_image_404(self):
fake_req = fakes.HTTPRequest.blank('/v2/fake/images/unknown')
@@ -457,7 +458,7 @@ class ImagesControllerTest(test.TestCase):
},
]
- self.assertDictListMatch(expected, response_list)
+ self.assertThat(expected, matchers.DictListMatches(response_list))
def test_get_image_details_with_limit(self):
request = fakes.HTTPRequest.blank('/v2/fake/images/detail?limit=2')
@@ -533,13 +534,14 @@ class ImagesControllerTest(test.TestCase):
}],
}]
- self.assertDictListMatch(expected, response_list)
+ self.assertThat(expected, matchers.DictListMatches(response_list))
href_parts = urlparse.urlparse(response_links[0]['href'])
self.assertEqual('/v2/fake/images', href_parts.path)
params = urlparse.parse_qs(href_parts.query)
- self.assertDictMatch({'limit': ['2'], 'marker': ['124']}, params)
+ self.assertThat({'limit': ['2'], 'marker': ['124']},
+ matchers.DictMatches(params))
def test_image_detail_filter_with_name(self):
image_service = self.mox.CreateMockAnything()
diff --git a/nova/tests/api/openstack/compute/test_limits.py b/nova/tests/api/openstack/compute/test_limits.py
index 32f2e1294..32e7ab9e0 100644
--- a/nova/tests/api/openstack/compute/test_limits.py
+++ b/nova/tests/api/openstack/compute/test_limits.py
@@ -30,6 +30,7 @@ from nova.api.openstack import xmlutil
import nova.context
from nova.openstack.common import jsonutils
from nova import test
+from nova.tests import matchers
TEST_LIMITS = [
@@ -862,7 +863,7 @@ class LimitsViewBuilderTest(test.TestCase):
output = self.view_builder.build(self.rate_limits,
self.absolute_limits)
- self.assertDictMatch(output, expected_limits)
+ self.assertThat(output, matchers.DictMatches(expected_limits))
def test_build_limits_empty_limits(self):
expected_limits = {"limits": {"rate": [],
@@ -871,7 +872,7 @@ class LimitsViewBuilderTest(test.TestCase):
abs_limits = {}
rate_limits = []
output = self.view_builder.build(rate_limits, abs_limits)
- self.assertDictMatch(output, expected_limits)
+ self.assertThat(output, matchers.DictMatches(expected_limits))
class LimitsXMLSerializationTest(test.TestCase):
diff --git a/nova/tests/api/openstack/compute/test_server_actions.py b/nova/tests/api/openstack/compute/test_server_actions.py
index de08c6124..ae2fde791 100644
--- a/nova/tests/api/openstack/compute/test_server_actions.py
+++ b/nova/tests/api/openstack/compute/test_server_actions.py
@@ -31,6 +31,7 @@ from nova.openstack.common import importutils
from nova import test
from nova.tests.api.openstack import fakes
from nova.tests.image import fake
+from nova.tests import matchers
from nova import utils
CONF = config.CONF
@@ -1052,7 +1053,7 @@ class TestServerActionXMLDeserializer(test.TestCase):
],
},
}
- self.assertDictMatch(request['body'], expected)
+ self.assertThat(request['body'], matchers.DictMatches(expected))
def test_rebuild_minimum(self):
serial_request = """<?xml version="1.0" encoding="UTF-8"?>
@@ -1065,7 +1066,7 @@ class TestServerActionXMLDeserializer(test.TestCase):
"imageRef": "http://localhost/images/1",
},
}
- self.assertDictMatch(request['body'], expected)
+ self.assertThat(request['body'], matchers.DictMatches(expected))
def test_rebuild_no_imageRef(self):
serial_request = """<?xml version="1.0" encoding="UTF-8"?>
diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py
index 4ef89806a..e329a5f7b 100644
--- a/nova/tests/api/openstack/compute/test_servers.py
+++ b/nova/tests/api/openstack/compute/test_servers.py
@@ -48,6 +48,7 @@ from nova import test
from nova.tests.api.openstack import fakes
from nova.tests import fake_network
from nova.tests.image import fake
+from nova.tests import matchers
from nova import utils
CONF = config.CONF
@@ -316,7 +317,7 @@ class ServersControllerTest(test.TestCase):
}
}
- self.assertDictMatch(res_dict, expected_server)
+ self.assertThat(res_dict, matchers.DictMatches(expected_server))
def test_get_server_with_active_status_by_id(self):
image_bookmark = "http://localhost/fake/images/10"
@@ -382,7 +383,7 @@ class ServersControllerTest(test.TestCase):
}
}
- self.assertDictMatch(res_dict, expected_server)
+ self.assertThat(res_dict, matchers.DictMatches(expected_server))
def test_get_server_with_id_image_ref_by_id(self):
image_ref = "10"
@@ -451,7 +452,7 @@ class ServersControllerTest(test.TestCase):
}
}
- self.assertDictMatch(res_dict, expected_server)
+ self.assertThat(res_dict, matchers.DictMatches(expected_server))
def test_get_server_addresses_from_cache(self):
pub0 = ('172.19.0.1', '172.19.0.2',)
@@ -502,7 +503,7 @@ class ServersControllerTest(test.TestCase):
],
},
}
- self.assertDictMatch(res_dict, expected)
+ self.assertThat(res_dict, matchers.DictMatches(expected))
def test_get_server_addresses_nonexistent_network(self):
url = '/v2/fake/servers/%s/ips/network_0' % FAKE_UUID
@@ -597,7 +598,7 @@ class ServersControllerTest(test.TestCase):
params = urlparse.parse_qs(href_parts.query)
expected_params = {'limit': ['3'],
'marker': [fakes.get_fake_uuid(2)]}
- self.assertDictMatch(expected_params, params)
+ self.assertThat(params, matchers.DictMatches(expected_params))
def test_get_servers_with_limit_bad_value(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers?limit=aaa')
@@ -619,7 +620,7 @@ class ServersControllerTest(test.TestCase):
self.assertEqual('/v2/fake/servers', href_parts.path)
params = urlparse.parse_qs(href_parts.query)
expected = {'limit': ['3'], 'marker': [fakes.get_fake_uuid(2)]}
- self.assertDictMatch(expected, params)
+ self.assertThat(params, matchers.DictMatches(expected))
def test_get_server_details_with_limit_bad_value(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers/detail?limit=aaa')
@@ -641,9 +642,9 @@ class ServersControllerTest(test.TestCase):
href_parts = urlparse.urlparse(servers_links[0]['href'])
self.assertEqual('/v2/fake/servers', href_parts.path)
params = urlparse.parse_qs(href_parts.query)
-
- self.assertDictMatch({'limit': ['3'], 'blah': ['2:t'],
- 'marker': [fakes.get_fake_uuid(2)]}, params)
+ expected = {'limit': ['3'], 'blah': ['2:t'],
+ 'marker': [fakes.get_fake_uuid(2)]}
+ self.assertThat(params, matchers.DictMatches(expected))
def test_get_servers_with_too_big_limit(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers?limit=30')
@@ -3254,7 +3255,7 @@ class TestServerCreateRequestXMLDeserializer(test.TestCase):
],
},
}
- self.assertDictMatch(request['body'], expected)
+ self.assertThat(request['body'], matchers.DictMatches(expected))
def test_spec_request(self):
image_bookmark_link = ("http://servers.api.openstack.org/1234/"
@@ -3699,7 +3700,7 @@ class ServersViewBuilderTest(test.TestCase):
}
output = self.view_builder.basic(self.request, self.instance)
- self.assertDictMatch(output, expected_server)
+ self.assertThat(output, matchers.DictMatches(expected_server))
def test_build_server_with_project_id(self):
expected_server = {
@@ -3721,7 +3722,7 @@ class ServersViewBuilderTest(test.TestCase):
}
output = self.view_builder.basic(self.request, self.instance)
- self.assertDictMatch(output, expected_server)
+ self.assertThat(output, matchers.DictMatches(expected_server))
def test_build_server_detail(self):
image_bookmark = "http://localhost/fake/images/5"
@@ -3780,7 +3781,7 @@ class ServersViewBuilderTest(test.TestCase):
}
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output, expected_server)
+ self.assertThat(output, matchers.DictMatches(expected_server))
def test_build_server_detail_with_fault(self):
self.instance['vm_state'] = vm_states.ERROR
@@ -3854,7 +3855,7 @@ class ServersViewBuilderTest(test.TestCase):
self.request.context = context.RequestContext('fake', 'fake')
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output, expected_server)
+ self.assertThat(output, matchers.DictMatches(expected_server))
def test_build_server_detail_with_fault_no_details_not_admin(self):
self.instance['vm_state'] = vm_states.ERROR
@@ -3872,7 +3873,8 @@ class ServersViewBuilderTest(test.TestCase):
self.request.context = context.RequestContext('fake', 'fake')
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output['server']['fault'], expected_fault)
+ self.assertThat(output['server']['fault'],
+ matchers.DictMatches(expected_fault))
def test_build_server_detail_with_fault_admin(self):
self.instance['vm_state'] = vm_states.ERROR
@@ -3891,7 +3893,8 @@ class ServersViewBuilderTest(test.TestCase):
self.request.context = context.get_admin_context()
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output['server']['fault'], expected_fault)
+ self.assertThat(output['server']['fault'],
+ matchers.DictMatches(expected_fault))
def test_build_server_detail_with_fault_no_details_admin(self):
self.instance['vm_state'] = vm_states.ERROR
@@ -3909,7 +3912,8 @@ class ServersViewBuilderTest(test.TestCase):
self.request.context = context.get_admin_context()
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output['server']['fault'], expected_fault)
+ self.assertThat(output['server']['fault'],
+ matchers.DictMatches(expected_fault))
def test_build_server_detail_with_fault_but_active(self):
self.instance['vm_state'] = vm_states.ACTIVE
@@ -3990,7 +3994,7 @@ class ServersViewBuilderTest(test.TestCase):
}
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output, expected_server)
+ self.assertThat(output, matchers.DictMatches(expected_server))
def test_build_server_detail_with_accessipv4(self):
@@ -4052,7 +4056,7 @@ class ServersViewBuilderTest(test.TestCase):
}
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output, expected_server)
+ self.assertThat(output, matchers.DictMatches(expected_server))
def test_build_server_detail_with_accessipv6(self):
@@ -4114,7 +4118,7 @@ class ServersViewBuilderTest(test.TestCase):
}
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output, expected_server)
+ self.assertThat(output, matchers.DictMatches(expected_server))
def test_build_server_detail_with_metadata(self):
@@ -4178,7 +4182,7 @@ class ServersViewBuilderTest(test.TestCase):
}
output = self.view_builder.show(self.request, self.instance)
- self.assertDictMatch(output, expected_server)
+ self.assertThat(output, matchers.DictMatches(expected_server))
class ServerXMLSerializationTest(test.TestCase):
diff --git a/nova/tests/api/openstack/compute/test_versions.py b/nova/tests/api/openstack/compute/test_versions.py
index 4520faa48..d59270bd6 100644
--- a/nova/tests/api/openstack/compute/test_versions.py
+++ b/nova/tests/api/openstack/compute/test_versions.py
@@ -26,6 +26,7 @@ from nova.openstack.common import jsonutils
from nova import test
from nova.tests.api.openstack import common
from nova.tests.api.openstack import fakes
+from nova.tests import matchers
from nova import utils
@@ -346,7 +347,8 @@ class VersionsTest(test.TestCase):
},
], }
- self.assertDictMatch(expected, jsonutils.loads(res.body))
+ self.assertThat(jsonutils.loads(res.body),
+ matchers.DictMatches(expected))
def test_multi_choice_image_xml(self):
req = webob.Request.blank('/images/1')
@@ -416,7 +418,8 @@ class VersionsTest(test.TestCase):
},
], }
- self.assertDictMatch(expected, jsonutils.loads(res.body))
+ self.assertThat(jsonutils.loads(res.body),
+ matchers.DictMatches(expected))
class VersionsViewBuilderTests(test.TestCase):
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index f894f3305..3b2c00b32 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -60,6 +60,7 @@ from nova.tests.db.fakes import FakeModel
from nova.tests import fake_network
from nova.tests import fake_network_cache_model
from nova.tests.image import fake as fake_image
+from nova.tests import matchers
from nova import utils
from nova.virt import fake
from nova.volume import cinder
@@ -4508,7 +4509,7 @@ class ComputeAPITestCase(BaseTestCase):
]
bdms.sort()
expected_result.sort()
- self.assertDictListMatch(bdms, expected_result)
+ self.assertThat(bdms, matchers.DictListMatches(expected_result))
self.compute_api._update_block_device_mapping(
self.context, instance_types.get_default_instance_type(),
@@ -4544,7 +4545,7 @@ class ComputeAPITestCase(BaseTestCase):
{'no_device': True, 'device_name': '/dev/sdd4'}]
bdms.sort()
expected_result.sort()
- self.assertDictListMatch(bdms, expected_result)
+ self.assertThat(bdms, matchers.DictListMatches(expected_result))
for bdm in db.block_device_mapping_get_all_by_instance(
self.context, instance['uuid']):
@@ -5055,7 +5056,8 @@ class ComputeAPIAggrTestCase(BaseTestCase):
metadata['foo_key1'] = None
expected = self.api.update_aggregate_metadata(self.context,
aggr['id'], metadata)
- self.assertDictMatch(expected['metadata'], {'foo_key2': 'foo_value2'})
+ self.assertThat(expected['metadata'],
+ matchers.DictMatches({'foo_key2': 'foo_value2'}))
def test_delete_aggregate(self):
"""Ensure we can delete an aggregate."""
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 13e090cef..e8baf4353 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -28,6 +28,7 @@ from nova.image import glance
from nova import test
from nova.tests.api.openstack import fakes
from nova.tests.glance import stubs as glance_stubs
+from nova.tests import matchers
class NullWriter(object):
@@ -155,10 +156,10 @@ class TestGlanceImageService(test.TestCase):
'properties': {'instance_id': '42', 'user_id': 'fake'},
'owner': None,
}
- self.assertDictMatch(image_meta, expected)
+ self.assertThat(image_meta, matchers.DictMatches(expected))
image_metas = self.service.detail(self.context)
- self.assertDictMatch(image_metas[0], expected)
+ self.assertThat(image_metas[0], matchers.DictMatches(expected))
def test_create_without_instance_id(self):
"""
@@ -188,7 +189,7 @@ class TestGlanceImageService(test.TestCase):
'owner': None,
}
actual = self.service.show(self.context, image_id)
- self.assertDictMatch(actual, expected)
+ self.assertThat(actual, matchers.DictMatches(expected))
def test_create(self):
fixture = self._make_fixture(name='test image')
@@ -259,7 +260,7 @@ class TestGlanceImageService(test.TestCase):
'owner': None,
}
- self.assertDictMatch(meta, expected)
+ self.assertThat(meta, matchers.DictMatches(expected))
i = i + 1
def test_detail_limit(self):
@@ -315,7 +316,7 @@ class TestGlanceImageService(test.TestCase):
'deleted': None,
'owner': None,
}
- self.assertDictMatch(meta, expected)
+ self.assertThat(meta, matchers.DictMatches(expected))
i = i + 1
def test_detail_invalid_marker(self):
diff --git a/nova/tests/matchers.py b/nova/tests/matchers.py
new file mode 100644
index 000000000..c3b88d2e5
--- /dev/null
+++ b/nova/tests/matchers.py
@@ -0,0 +1,196 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2012 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Matcher classes to be used inside of the testtools assertThat framework."""
+
+import pprint
+
+
+class DictKeysMismatch(object):
+ def __init__(self, d1only, d2only):
+ self.d1only = d1only
+ self.d2only = d2only
+
+ def describe(self):
+ return ('Keys in d1 and not d2: %(d1only)s.'
+ ' Keys in d2 and not d1: %(d2only)s' % self.__dict__)
+
+ def get_details(self):
+ return {}
+
+
+class DictMismatch(object):
+ def __init__(self, key, d1_value, d2_value):
+ self.key = key
+ self.d1_value = d1_value
+ self.d2_value = d2_value
+
+ def describe(self):
+ return ("Dictionaries do not match at %(key)s."
+ " d1: %(d1_value)s d2: %(d2_value)s" % self.__dict__)
+
+ def get_details(self):
+ return {}
+
+
+class DictMatches(object):
+
+ def __init__(self, d1, approx_equal=False, tolerance=0.001):
+ self.d1 = d1
+ self.approx_equal = approx_equal
+ self.tolerance = tolerance
+
+ def __str__(self):
+ return 'DictMatches(%s)' % (pprint.pformat(self.d1))
+
+ # Useful assertions
+ def match(self, d2):
+ """Assert two dicts are equivalent.
+
+ This is a 'deep' match in the sense that it handles nested
+ dictionaries appropriately.
+
+ NOTE:
+
+ If you don't care (or don't know) a given value, you can specify
+ the string DONTCARE as the value. This will cause that dict-item
+ to be skipped.
+
+ """
+
+ d1keys = set(self.d1.keys())
+ d2keys = set(d2.keys())
+ if d1keys != d2keys:
+ d1only = d1keys - d2keys
+ d2only = d2keys - d1keys
+ return DictKeysMismatch(d1only, d2only)
+
+ for key in d1keys:
+ d1value = self.d1[key]
+ d2value = d2[key]
+ try:
+ error = abs(float(d1value) - float(d2value))
+ within_tolerance = error <= self.tolerance
+ except (ValueError, TypeError):
+ # If both values aren't convertible to float, just ignore
+ # ValueError if arg is a str, TypeError if it's something else
+ # (like None)
+ within_tolerance = False
+
+ if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'):
+ matcher = DictMatches(d1value)
+ did_match = matcher.match(d2value)
+ if did_match is not None:
+ return did_match
+ elif 'DONTCARE' in (d1value, d2value):
+ continue
+ elif self.approx_equal and within_tolerance:
+ continue
+ elif d1value != d2value:
+ return DictMismatch(key, d1value, d2value)
+
+
+class ListLengthMismatch(object):
+ def __init__(self, len1, len2):
+ self.len1 = len1
+ self.len2 = len2
+
+ def describe(self):
+ return ('Length mismatch: len(L1)=%(len1)d != '
+ 'len(L2)=%(len2)d' % self.__dict__)
+
+ def get_details(self):
+ return {}
+
+
+class DictListMatches(object):
+
+ def __init__(self, l1, approx_equal=False, tolerance=0.001):
+ self.l1 = l1
+ self.approx_equal = approx_equal
+ self.tolerance = tolerance
+
+ def __str__(self):
+ return 'DictListMatches(%s)' % (pprint.pformat(self.l1))
+
+ # Useful assertions
+ def match(self, l2):
+ """Assert a list of dicts are equivalent."""
+
+ l1count = len(self.l1)
+ l2count = len(l2)
+ if l1count != l2count:
+ return ListLengthMismatch(l1count, l2count)
+
+ for d1, d2 in zip(self.l1, l2):
+ matcher = DictMatches(d2,
+ approx_equal=self.approx_equal,
+ tolerance=self.tolerance)
+ did_match = matcher.match(d1)
+ if did_match:
+ return did_match
+
+
+class SubDictMismatch(object):
+ def __init__(self,
+ key=None,
+ sub_value=None,
+ super_value=None,
+ keys=False):
+ self.key = key
+ self.sub_value = sub_value
+ self.super_value = super_value
+ self.keys = keys
+
+ def describe(self):
+ if self.keys:
+ return "Keys between dictionaries did not match"
+ else:
+ return("Dictionaries do not match at %s. d1: %s d2: %s"
+ % (self.key,
+ self.super_value,
+ self.sub_value))
+
+ def get_details(self):
+ return {}
+
+
+class IsSubDictOf(object):
+
+ def __init__(self, super_dict):
+ self.super_dict = super_dict
+
+ def __str__(self):
+ return 'IsSubDictOf(%s)' % (self.super_dict)
+
+ def match(self, sub_dict):
+ """Assert a sub_dict is subset of super_dict."""
+ if not set(sub_dict.keys()).issubset(set(self.super_dict.keys())):
+ return SubDictMismatch(keys=True)
+ for k, sub_value in sub_dict.items():
+ super_value = self.super_dict[k]
+ if isinstance(sub_value, dict):
+ matcher = IsSubDictOf(super_value)
+ did_match = matcher.match(sub_value)
+ if did_match is not None:
+ return did_match
+ elif 'DONTCARE' in (sub_value, super_value):
+ continue
+ else:
+ if sub_value != super_value:
+ return SubDictMismatch(k, sub_value, super_value)
diff --git a/nova/tests/network/test_manager.py b/nova/tests/network/test_manager.py
index 77fccd904..698ce8f59 100644
--- a/nova/tests/network/test_manager.py
+++ b/nova/tests/network/test_manager.py
@@ -32,6 +32,7 @@ import nova.policy
from nova import test
from nova.tests import fake_ldap
from nova.tests import fake_network
+from nova.tests import matchers
from nova import utils
@@ -168,7 +169,7 @@ class FlatNetworkTestCase(test.TestCase):
'bridge_interface': None,
'vlan': None}
- self.assertDictMatch(nw, check)
+ self.assertThat(nw, matchers.DictMatches(check))
check = {'broadcast': '192.168.%d.255' % nid,
'dhcp_server': '192.168.1.1',
@@ -184,13 +185,13 @@ class FlatNetworkTestCase(test.TestCase):
'00000000-0000-0000-0000-00000000000000%02d' % nid,
'should_create_vlan': False,
'should_create_bridge': False}
- self.assertDictMatch(info, check)
+ self.assertThat(info, matchers.DictMatches(check))
check = [{'enabled': 'DONTCARE',
'ip': '2001:db8:0:1::%x' % nid,
'netmask': 64,
'gateway': 'fe80::def'}]
- self.assertDictListMatch(info['ip6s'], check)
+ self.assertThat(info['ip6s'], matchers.DictListMatches(check))
num_fixed_ips = len(info['ips'])
check = [{'enabled': 'DONTCARE',
@@ -198,7 +199,7 @@ class FlatNetworkTestCase(test.TestCase):
'netmask': '255.255.255.0',
'gateway': '192.168.%d.1' % nid}
for ip_num in xrange(1, num_fixed_ips + 1)]
- self.assertDictListMatch(info['ips'], check)
+ self.assertThat(info['ips'], matchers.DictListMatches(check))
def test_validate_networks(self):
self.mox.StubOutWithMock(db, 'network_get')
diff --git a/nova/tests/scheduler/test_host_manager.py b/nova/tests/scheduler/test_host_manager.py
index d7d732d34..0984cbf80 100644
--- a/nova/tests/scheduler/test_host_manager.py
+++ b/nova/tests/scheduler/test_host_manager.py
@@ -24,6 +24,7 @@ from nova import exception
from nova.openstack.common import timeutils
from nova.scheduler import host_manager
from nova import test
+from nova.tests import matchers
from nova.tests.scheduler import fakes
@@ -92,7 +93,7 @@ class HostManagerTestCase(test.TestCase):
def test_update_service_capabilities(self):
service_states = self.host_manager.service_states
- self.assertDictMatch(service_states, {})
+ self.assertEqual(len(service_states.keys()), 0)
self.mox.StubOutWithMock(timeutils, 'utcnow')
timeutils.utcnow().AndReturn(31337)
timeutils.utcnow().AndReturn(31339)
@@ -116,11 +117,11 @@ class HostManagerTestCase(test.TestCase):
expected = {('host1', 'node1'): host1_compute_capabs,
('host2', 'node2'): host2_compute_capabs}
- self.assertDictMatch(service_states, expected)
+ self.assertThat(service_states, matchers.DictMatches(expected))
def test_update_service_capabilities_node_key(self):
service_states = self.host_manager.service_states
- self.assertDictMatch(service_states, {})
+ self.assertThat(service_states, matchers.DictMatches({}))
host1_cap = {'hypervisor_hostname': 'host1-hvhn'}
host2_cap = {}
@@ -135,7 +136,7 @@ class HostManagerTestCase(test.TestCase):
host2_cap['timestamp'] = 31338
expected = {('host1', 'host1-hvhn'): host1_cap,
('host2', None): host2_cap}
- self.assertDictMatch(service_states, expected)
+ self.assertThat(service_states, matchers.DictMatches(expected))
def test_get_all_host_states(self):
diff --git a/nova/tests/scheduler/test_least_cost.py b/nova/tests/scheduler/test_least_cost.py
index 3689a30bd..1d180d718 100644
--- a/nova/tests/scheduler/test_least_cost.py
+++ b/nova/tests/scheduler/test_least_cost.py
@@ -19,6 +19,7 @@ from nova import context
from nova.scheduler import host_manager
from nova.scheduler import least_cost
from nova import test
+from nova.tests import matchers
from nova.tests.scheduler import fakes
@@ -92,11 +93,11 @@ class TestWeightedHost(test.TestCase):
def test_dict_conversion_without_host_state(self):
host = least_cost.WeightedHost('someweight')
expected = {'weight': 'someweight'}
- self.assertDictMatch(host.to_dict(), expected)
+ self.assertThat(host.to_dict(), matchers.DictMatches(expected))
def test_dict_conversion_with_host_state(self):
host_state = host_manager.HostState('somehost', None)
host = least_cost.WeightedHost('someweight', host_state)
expected = {'weight': 'someweight',
'host': 'somehost'}
- self.assertDictMatch(host.to_dict(), expected)
+ self.assertThat(host.to_dict(), matchers.DictMatches(expected))
diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py
index 9d31a0cc9..5fa3fbacd 100644
--- a/nova/tests/scheduler/test_scheduler.py
+++ b/nova/tests/scheduler/test_scheduler.py
@@ -36,6 +36,7 @@ from nova.openstack.common import timeutils
from nova.scheduler import driver
from nova.scheduler import manager
from nova import test
+from nova.tests import matchers
from nova.tests.scheduler import fakes
from nova import utils
@@ -136,7 +137,7 @@ class SchedulerManagerTestCase(test.TestCase):
'local_gb_used': 512,
'memory_mb': 1024,
'memory_mb_used': 512}}
- self.assertDictMatch(result, expected)
+ self.assertThat(result, matchers.DictMatches(expected))
def _mox_schedule_method_helper(self, method_name):
# Make sure the method exists that we're going to test call
@@ -719,7 +720,7 @@ class SchedulerDriverModuleTestCase(test.TestCase):
result = driver.encode_instance(instance, True)
expected = {'id': instance['id'], '_is_precooked': False}
- self.assertDictMatch(result, expected)
+ self.assertThat(result, matchers.DictMatches(expected))
# Orig dict not changed
self.assertNotEqual(result, instance)
@@ -727,6 +728,6 @@ class SchedulerDriverModuleTestCase(test.TestCase):
expected = {}
expected.update(instance)
expected['_is_precooked'] = True
- self.assertDictMatch(result, expected)
+ self.assertThat(result, matchers.DictMatches(expected))
# Orig dict not changed
self.assertNotEqual(result, instance)
diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py
index c2a63fe25..afb366624 100644
--- a/nova/tests/test_api.py
+++ b/nova/tests/test_api.py
@@ -41,6 +41,7 @@ from nova import exception
from nova import flags
from nova.openstack.common import timeutils
from nova import test
+from nova.tests import matchers
class FakeHttplibSocket(object):
@@ -160,7 +161,7 @@ class Ec2utilsTestCase(test.TestCase):
'virtual_name': 'ephemeral0'}}}
out_dict = ec2utils.dict_from_dotted_str(in_str)
- self.assertDictMatch(out_dict, expected_dict)
+ self.assertThat(out_dict, matchers.DictMatches(expected_dict))
def test_properties_root_defice_name(self):
mappings = [{"device": "/dev/sda1", "virtual": "root"}]
@@ -206,8 +207,8 @@ class Ec2utilsTestCase(test.TestCase):
'device': '/dev/sdc1'},
{'virtual': 'ephemeral1',
'device': '/dev/sdc1'}]
- self.assertDictListMatch(block_device.mappings_prepend_dev(mappings),
- expected_result)
+ self.assertThat(block_device.mappings_prepend_dev(mappings),
+ matchers.DictListMatches(expected_result))
class ApiEc2TestCase(test.TestCase):
diff --git a/nova/tests/test_bdm.py b/nova/tests/test_bdm.py
index 381ed8070..2d0349534 100644
--- a/nova/tests/test_bdm.py
+++ b/nova/tests/test_bdm.py
@@ -22,6 +22,7 @@ Tests for Block Device Mapping Code.
from nova.api.ec2 import cloud
from nova.api.ec2 import ec2utils
from nova import test
+from nova.tests import matchers
class BlockDeviceMappingEc2CloudTestCase(test.TestCase):
@@ -41,7 +42,7 @@ class BlockDeviceMappingEc2CloudTestCase(test.TestCase):
def _assertApply(self, action, bdm_list):
for bdm, expected_result in bdm_list:
- self.assertDictMatch(action(bdm), expected_result)
+ self.assertThat(action(bdm), matchers.DictMatches(expected_result))
def test_parse_block_device_mapping(self):
self.stubs.Set(ec2utils,
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index ac66a25c1..7a71a1247 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -28,6 +28,7 @@ from nova import exception
from nova import flags
from nova.openstack.common import timeutils
from nova import test
+from nova.tests import matchers
from nova import utils
CONF = config.CONF
@@ -621,14 +622,16 @@ class AggregateDBApiTestCase(test.TestCase):
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt)
expected_metadata = db.aggregate_metadata_get(ctxt, result['id'])
- self.assertDictMatch(expected_metadata, _get_fake_aggr_metadata())
+ self.assertThat(expected_metadata,
+ matchers.DictMatches(_get_fake_aggr_metadata()))
def test_aggregate_create_delete_create_with_metadata(self):
"""Ensure aggregate metadata is deleted bug 1052479."""
ctxt = context.get_admin_context()
result = _create_aggregate(context=ctxt)
expected_metadata = db.aggregate_metadata_get(ctxt, result['id'])
- self.assertDictMatch(expected_metadata, _get_fake_aggr_metadata())
+ self.assertThat(expected_metadata,
+ matchers.DictMatches(_get_fake_aggr_metadata()))
db.aggregate_delete(ctxt, result['id'])
result = _create_aggregate(metadata=None)
expected_metadata = db.aggregate_metadata_get(ctxt, result['id'])
@@ -750,7 +753,8 @@ class AggregateDBApiTestCase(test.TestCase):
values['metadata'] = _get_fake_aggr_metadata()
db.aggregate_update(ctxt, 1, values)
expected = db.aggregate_metadata_get(ctxt, result.id)
- self.assertDictMatch(_get_fake_aggr_metadata(), expected)
+ self.assertThat(_get_fake_aggr_metadata(),
+ matchers.DictMatches(expected))
def test_aggregate_update_with_existing_metadata(self):
"""Ensure an aggregate can be updated with existing metadata."""
@@ -761,7 +765,7 @@ class AggregateDBApiTestCase(test.TestCase):
values['metadata']['fake_key1'] = 'foo'
db.aggregate_update(ctxt, 1, values)
expected = db.aggregate_metadata_get(ctxt, result.id)
- self.assertDictMatch(values['metadata'], expected)
+ self.assertThat(values['metadata'], matchers.DictMatches(expected))
def test_aggregate_update_raise_not_found(self):
"""Ensure AggregateNotFound is raised when updating an aggregate."""
@@ -807,7 +811,7 @@ class AggregateDBApiTestCase(test.TestCase):
metadata = _get_fake_aggr_metadata()
db.aggregate_metadata_add(ctxt, result.id, metadata)
expected = db.aggregate_metadata_get(ctxt, result.id)
- self.assertDictMatch(metadata, expected)
+ self.assertThat(metadata, matchers.DictMatches(expected))
def test_aggregate_metadata_update(self):
"""Ensure we can update metadata for the aggregate."""
@@ -820,7 +824,7 @@ class AggregateDBApiTestCase(test.TestCase):
db.aggregate_metadata_add(ctxt, result.id, new_metadata)
expected = db.aggregate_metadata_get(ctxt, result.id)
metadata[key] = 'foo'
- self.assertDictMatch(metadata, expected)
+ self.assertThat(metadata, matchers.DictMatches(expected))
def test_aggregate_metadata_delete(self):
"""Ensure we can delete metadata for the aggregate."""
@@ -831,7 +835,7 @@ class AggregateDBApiTestCase(test.TestCase):
db.aggregate_metadata_delete(ctxt, result.id, metadata.keys()[0])
expected = db.aggregate_metadata_get(ctxt, result.id)
del metadata[metadata.keys()[0]]
- self.assertDictMatch(metadata, expected)
+ self.assertThat(metadata, matchers.DictMatches(expected))
def test_aggregate_metadata_delete_raise_not_found(self):
"""Ensure AggregateMetadataNotFound is raised when deleting."""
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index 36c2bba7c..612fa1db9 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -46,6 +46,7 @@ from nova import test
from nova.tests import fake_libvirt_utils
from nova.tests import fake_network
import nova.tests.image.fake
+from nova.tests import matchers
from nova import utils
from nova.virt.disk import api as disk
from nova.virt import driver
@@ -631,7 +632,7 @@ class LibvirtConnTestCase(test.TestCase):
'id': 'fake'
}
result = conn.get_volume_connector(volume)
- self.assertDictMatch(expected, result)
+ self.assertThat(expected, matchers.DictMatches(result))
def test_get_guest_config(self):
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
@@ -1924,11 +1925,11 @@ class LibvirtConnTestCase(test.TestCase):
self.mox.ReplayAll()
return_value = conn.check_can_live_migrate_destination(self.context,
instance_ref, compute_info, compute_info, True)
- self.assertDictMatch(return_value,
- {"filename": "file",
- 'disk_available_mb': 409600,
- "disk_over_commit": False,
- "block_migration": True})
+ self.assertThat({"filename": "file",
+ 'disk_available_mb': 409600,
+ "disk_over_commit": False,
+ "block_migration": True},
+ matchers.DictMatches(return_value))
def test_check_can_live_migrate_dest_all_pass_no_block_migration(self):
instance_ref = db.instance_create(self.context, self.test_instance)
@@ -1950,11 +1951,11 @@ class LibvirtConnTestCase(test.TestCase):
self.mox.ReplayAll()
return_value = conn.check_can_live_migrate_destination(self.context,
instance_ref, compute_info, compute_info, False)
- self.assertDictMatch(return_value,
- {"filename": "file",
- "block_migration": False,
- "disk_over_commit": False,
- "disk_available_mb": None})
+ self.assertThat({"filename": "file",
+ "block_migration": False,
+ "disk_over_commit": False,
+ "disk_available_mb": None},
+ matchers.DictMatches(return_value))
def test_check_can_live_migrate_dest_incompatible_cpu_raises(self):
instance_ref = db.instance_create(self.context, self.test_instance)
diff --git a/nova/tests/test_matchers.py b/nova/tests/test_matchers.py
new file mode 100644
index 000000000..b764b3d45
--- /dev/null
+++ b/nova/tests/test_matchers.py
@@ -0,0 +1,144 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import testtools
+from testtools.tests.matchers import helpers
+
+from nova.tests import matchers
+
+
+class TestDictMatches(testtools.TestCase, helpers.TestMatchersInterface):
+
+ matches_matcher = matchers.DictMatches(
+ {'foo': 'bar', 'baz': 'DONTCARE',
+ 'cat': {'tabby': True, 'fluffy': False}}
+ )
+
+ matches_matches = [
+ {'foo': 'bar', 'baz': 'noox', 'cat': {'tabby': True, 'fluffy': False}},
+ {'foo': 'bar', 'baz': 'quux', 'cat': {'tabby': True, 'fluffy': False}},
+ ]
+
+ matches_mismatches = [
+ {},
+ {'foo': 'bar', 'baz': 'qux'},
+ {'foo': 'bop', 'baz': 'qux',
+ 'cat': {'tabby': True, 'fluffy': False}},
+ {'foo': 'bar', 'baz': 'quux',
+ 'cat': {'tabby': True, 'fluffy': True}},
+ {'foo': 'bar', 'cat': {'tabby': True, 'fluffy': False}},
+ ]
+
+ str_examples = [
+ ("DictMatches({'baz': 'DONTCARE', 'cat':"
+ " {'fluffy': False, 'tabby': True}, 'foo': 'bar'})",
+ matches_matcher),
+ ]
+
+ describe_examples = [
+ ("Keys in d1 and not d2: set(['foo', 'baz', 'cat'])."
+ " Keys in d2 and not d1: set([])", {}, matches_matcher),
+ ("Dictionaries do not match at fluffy. d1: False d2: True",
+ {'foo': 'bar', 'baz': 'quux',
+ 'cat': {'tabby': True, 'fluffy': True}}, matches_matcher),
+ ("Dictionaries do not match at foo. d1: bar d2: bop",
+ {'foo': 'bop', 'baz': 'quux',
+ 'cat': {'tabby': True, 'fluffy': False}}, matches_matcher),
+ ]
+
+
+class TestDictListMatches(testtools.TestCase, helpers.TestMatchersInterface):
+
+ matches_matcher = matchers.DictListMatches(
+ [{'foo': 'bar', 'baz': 'DONTCARE',
+ 'cat': {'tabby': True, 'fluffy': False}},
+ {'dog': 'yorkie'},
+ ])
+
+ matches_matches = [
+ [{'foo': 'bar', 'baz': 'qoox',
+ 'cat': {'tabby': True, 'fluffy': False}},
+ {'dog': 'yorkie'}],
+ [{'foo': 'bar', 'baz': False,
+ 'cat': {'tabby': True, 'fluffy': False}},
+ {'dog': 'yorkie'}],
+ ]
+
+ matches_mismatches = [
+ [],
+ {},
+ [{'foo': 'bar', 'baz': 'qoox',
+ 'cat': {'tabby': True, 'fluffy': True}},
+ {'dog': 'yorkie'}],
+ [{'foo': 'bar', 'baz': False,
+ 'cat': {'tabby': True, 'fluffy': False}},
+ {'cat': 'yorkie'}],
+ [{'foo': 'bop', 'baz': False,
+ 'cat': {'tabby': True, 'fluffy': False}},
+ {'dog': 'yorkie'}],
+ ]
+
+ str_examples = [
+ ("DictListMatches([{'baz': 'DONTCARE', 'cat':"
+ " {'fluffy': False, 'tabby': True}, 'foo': 'bar'},\n"
+ " {'dog': 'yorkie'}])",
+ matches_matcher),
+ ]
+
+ describe_examples = [
+ ("Length mismatch: len(L1)=2 != len(L2)=0", {}, matches_matcher),
+ ("Dictionaries do not match at fluffy. d1: True d2: False",
+ [{'foo': 'bar', 'baz': 'qoox',
+ 'cat': {'tabby': True, 'fluffy': True}},
+ {'dog': 'yorkie'}],
+ matches_matcher),
+ ]
+
+
+class TestDictMatches(testtools.TestCase, helpers.TestMatchersInterface):
+
+ matches_matcher = matchers.IsSubDictOf(
+ {'foo': 'bar', 'baz': 'DONTCARE',
+ 'cat': {'tabby': True, 'fluffy': False}}
+ )
+
+ matches_matches = [
+ {'foo': 'bar', 'baz': 'noox', 'cat': {'tabby': True, 'fluffy': False}},
+ {'foo': 'bar', 'baz': 'quux'}
+ ]
+
+ matches_mismatches = [
+ {'foo': 'bop', 'baz': 'qux',
+ 'cat': {'tabby': True, 'fluffy': False}},
+ {'foo': 'bar', 'baz': 'quux',
+ 'cat': {'tabby': True, 'fluffy': True}},
+ {'foo': 'bar', 'cat': {'tabby': True, 'fluffy': False}, 'dog': None},
+ ]
+
+ str_examples = [
+ ("IsSubDictOf({'foo': 'bar', 'baz': 'DONTCARE',"
+ " 'cat': {'fluffy': False, 'tabby': True}})",
+ matches_matcher),
+ ]
+
+ describe_examples = [
+ ("Dictionaries do not match at fluffy. d1: False d2: True",
+ {'foo': 'bar', 'baz': 'quux',
+ 'cat': {'tabby': True, 'fluffy': True}}, matches_matcher),
+ ("Dictionaries do not match at foo. d1: bar d2: bop",
+ {'foo': 'bop', 'baz': 'quux',
+ 'cat': {'tabby': True, 'fluffy': False}}, matches_matcher),
+ ]
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index f5a5969aa..50ed9cd2a 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -42,6 +42,7 @@ from nova.tests.db import fakes as db_fakes
from nova.tests import fake_network
from nova.tests import fake_utils
import nova.tests.image.fake as fake_image
+from nova.tests import matchers
from nova.tests.xenapi import stubs
from nova.virt import fake
from nova.virt.xenapi import agent
@@ -361,7 +362,7 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
}
instance = self._create_instance()
expected = self.conn.get_diagnostics(instance)
- self.assertDictMatch(fake_diagnostics, expected)
+ self.assertThat(fake_diagnostics, matchers.DictMatches(expected))
def test_instance_snapshot_fails_with_no_primary_vdi(self):
def create_bad_vbd(session, vm_ref, vdi_ref, userdevice,
@@ -2140,7 +2141,8 @@ class XenAPIAggregateTestCase(stubs.XenAPITestBase):
self.conn._pool.add_to_aggregate(self.context, aggregate, "host")
result = db.aggregate_get(self.context, aggregate.id)
self.assertTrue(fake_init_pool.called)
- self.assertDictMatch(self.fake_metadata, result.metadetails)
+ self.assertThat(self.fake_metadata,
+ matchers.DictMatches(result.metadetails))
def test_join_slave(self):
"""Ensure join_slave gets called when the request gets to master."""
@@ -2218,8 +2220,9 @@ class XenAPIAggregateTestCase(stubs.XenAPITestBase):
self.conn._pool.remove_from_aggregate(self.context, aggregate, "host")
result = db.aggregate_get(self.context, aggregate.id)
self.assertTrue(fake_clear_pool.called)
- self.assertDictMatch({pool_states.POOL_FLAG: 'XenAPI',
- pool_states.KEY: pool_states.ACTIVE}, result.metadetails)
+ self.assertThat({pool_states.POOL_FLAG: 'XenAPI',
+ pool_states.KEY: pool_states.ACTIVE},
+ matchers.DictMatches(result.metadetails))
def test_remote_master_non_empty_pool(self):
"""Ensure AggregateError is raised if removing the master."""