diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-11-13 07:07:19 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-11-13 07:07:19 +0000 |
| commit | 136fd2f26b7b32e87f8ab9ff88025324e269c926 (patch) | |
| tree | 17ae1b75b4bd51fb4bbc0f5c0091181ac1294553 | |
| parent | 4262020dd36a77397b0b2b10e27d3874aae755eb (diff) | |
| parent | 8eea01449e7b43a5729df31df9f3f3ffeb55ec78 (diff) | |
| download | nova-136fd2f26b7b32e87f8ab9ff88025324e269c926.tar.gz nova-136fd2f26b7b32e87f8ab9ff88025324e269c926.tar.xz nova-136fd2f26b7b32e87f8ab9ff88025324e269c926.zip | |
Merge "Remove custom test assertions."
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.""" |
