diff --git a/contrib/rackspace/rackspace/tests/test_cloud_loadbalancer.py b/contrib/rackspace/rackspace/tests/test_cloud_loadbalancer.py
index 8c60a6c09a..cb2be90339 100644
--- a/contrib/rackspace/rackspace/tests/test_cloud_loadbalancer.py
+++ b/contrib/rackspace/rackspace/tests/test_cloud_loadbalancer.py
@@ -17,6 +17,7 @@ import json
import uuid
import mock
+import mox
import six
from heat.common import exception
@@ -1229,11 +1230,11 @@ class LoadBalancerTest(common.HeatTestCase):
template['Resources'][lb_name]['Properties']['metadata'] = {
'a': 1, 'b': 2}
expected_body = copy.deepcopy(self.expected_body)
- expected_body['metadata'] = [{'key': 'a', 'value': 1},
- {'key': 'b', 'value': 2}]
- rsrc, fake_loadbalancer = self._mock_loadbalancer(template,
- self.lb_name,
- expected_body)
+ expected_body['metadata'] = mox.SameElementsAs(
+ [{'key': 'a', 'value': 1},
+ {'key': 'b', 'value': 2}])
+ rsrc, fake_loadbalancer = self._mock_loadbalancer(
+ template, self.lb_name, expected_body)
self.m.ReplayAll()
scheduler.TaskRunner(rsrc.create)()
diff --git a/heat/tests/api/aws/test_api_ec2token.py b/heat/tests/api/aws/test_api_ec2token.py
index ffcda3d3df..dae129b53d 100644
--- a/heat/tests/api/aws/test_api_ec2token.py
+++ b/heat/tests/api/aws/test_api_ec2token.py
@@ -24,12 +24,13 @@ from heat.api.aws import ec2token
from heat.api.aws import exception
from heat.common import wsgi
from heat.tests import common
+from heat.tests import utils
class Ec2TokenTest(common.HeatTestCase):
- '''
+ """
Tests the Ec2Token middleware
- '''
+ """
def setUp(self):
super(Ec2TokenTest, self).setUp()
@@ -253,8 +254,9 @@ class Ec2TokenTest(common.HeatTestCase):
"path": "/v1",
"body_hash": body_hash}})
req_headers = {'Content-Type': 'application/json'}
- requests.post(req_url, data=req_creds, verify=verify, cert=cert,
- headers=req_headers).AndReturn(DummyHTTPResponse())
+ requests.post(
+ req_url, data=utils.JsonEquals(req_creds), verify=verify,
+ cert=cert, headers=req_headers).AndReturn(DummyHTTPResponse())
def test_call_ok(self):
dummy_conf = {'auth_uri': 'http://123:5000/v2.0'}
diff --git a/heat/tests/api/cfn/test_api_cfn_v1.py b/heat/tests/api/cfn/test_api_cfn_v1.py
index 17f9256cb1..ac7c7afc7b 100644
--- a/heat/tests/api/cfn/test_api_cfn_v1.py
+++ b/heat/tests/api/cfn/test_api_cfn_v1.py
@@ -33,10 +33,10 @@ policy_path = os.path.dirname(os.path.realpath(__file__)) + "/../../policy/"
class CfnStackControllerTest(common.HeatTestCase):
- '''
+ """
Tests the API class which acts as the WSGI controller,
the endpoint processing API requests after they are routed
- '''
+ """
def setUp(self):
super(CfnStackControllerTest, self).setUp()
@@ -333,7 +333,8 @@ class CfnStackControllerTest(common.HeatTestCase):
'DisableRollback': 'true',
'LastUpdatedTime': u'2012-07-09T09:13:11Z'}]}}}
- self.assertEqual(expected, response)
+ self.assertEqual(utils.recursive_sort(expected),
+ utils.recursive_sort(response))
def test_describe_arn(self):
# Format a dummy GET request to pass into the WSGI handler
@@ -417,7 +418,8 @@ class CfnStackControllerTest(common.HeatTestCase):
'DisableRollback': 'true',
'LastUpdatedTime': u'2012-07-09T09:13:11Z'}]}}}
- self.assertEqual(expected, response)
+ self.assertEqual(utils.recursive_sort(expected),
+ utils.recursive_sort(response))
def test_describe_arn_invalidtenant(self):
# Format a dummy GET request to pass into the WSGI handler
@@ -481,7 +483,7 @@ class CfnStackControllerTest(common.HeatTestCase):
self.assertIsInstance(result, exception.HeatInvalidParameterValueError)
def test_get_template_int_body(self):
- '''Test the internal _get_template function.'''
+ """Test the internal _get_template function."""
params = {'TemplateBody': "abcdef"}
dummy_req = self._dummy_GET_request(params)
result = self.controller._get_template(dummy_req)
diff --git a/heat/tests/api/cloudwatch/test_api_cloudwatch.py b/heat/tests/api/cloudwatch/test_api_cloudwatch.py
index 8cc85dab71..2e17dd0a36 100644
--- a/heat/tests/api/cloudwatch/test_api_cloudwatch.py
+++ b/heat/tests/api/cloudwatch/test_api_cloudwatch.py
@@ -73,11 +73,13 @@ class WatchControllerTest(common.HeatTestCase):
dims = [{'StackId': u'21617058-781e-4262-97ab-5f9df371ee52',
'Foo': 'bar'}]
- self.assertEqual([{'Name': 'StackId',
- 'Value': u'21617058-781e-4262-97ab-5f9df371ee52'},
- {'Name': 'Foo', 'Value': 'bar'}],
- self.controller._reformat_dimensions(dims)
- )
+ self.assertEqual(
+ utils.recursive_sort(
+ [{'Name': 'StackId',
+ 'Value': u'21617058-781e-4262-97ab-5f9df371ee52'},
+ {'Name': 'Foo',
+ 'Value': 'bar'}]),
+ utils.recursive_sort(self.controller._reformat_dimensions(dims)))
def test_enforce_default(self):
self.m.ReplayAll()
@@ -301,7 +303,9 @@ class WatchControllerTest(common.HeatTestCase):
'MetricName': u'ServiceFailure3'}]}}}
# First pass no query paramters filtering, should get all three
- self.assertEqual(expected, self.controller.list_metrics(dummy_req))
+ self.assertEqual(
+ utils.recursive_sort(expected),
+ utils.recursive_sort(self.controller.list_metrics(dummy_req)))
def test_list_metrics_filter_name(self):
@@ -358,7 +362,9 @@ class WatchControllerTest(common.HeatTestCase):
'Value': 1}],
'MetricName': u'ServiceFailure'}]}}}
# First pass no query paramters filtering, should get all three
- self.assertEqual(expected, self.controller.list_metrics(dummy_req))
+ self.assertEqual(
+ utils.recursive_sort(expected),
+ utils.recursive_sort(self.controller.list_metrics(dummy_req)))
def test_list_metrics_filter_namespace(self):
@@ -426,7 +432,9 @@ class WatchControllerTest(common.HeatTestCase):
{'Name': u'Value',
'Value': 1}],
'MetricName': u'ServiceFailure2'}]}}}
- self.assertEqual(expected, self.controller.list_metrics(dummy_req))
+ self.assertEqual(
+ utils.recursive_sort(expected),
+ utils.recursive_sort(self.controller.list_metrics(dummy_req)))
def test_put_metric_alarm(self):
# Not yet implemented, should raise HeatAPINotImplementedError
diff --git a/heat/tests/api/openstack_v1/test_views_common.py b/heat/tests/api/openstack_v1/test_views_common.py
index 981dcc542f..c9fbd377de 100644
--- a/heat/tests/api/openstack_v1/test_views_common.py
+++ b/heat/tests/api/openstack_v1/test_views_common.py
@@ -38,10 +38,12 @@ class TestViewsCommon(common.HeatTestCase):
self.setUpGetCollectionLinks()
links = views_common.get_collection_links(self.request, self.items)
- expected = 'http://example.com/fake/path?marker=id2&limit=2'
+ expected_params = {'marker': ['id2'], 'limit': ['2']}
next_link = filter(lambda link: link['rel'] == 'next', links).pop()
self.assertEqual('next', next_link['rel'])
- self.assertEqual(expected, next_link['href'])
+ url_path, url_params = next_link['href'].split('?', 1)
+ self.assertEqual(url_path, self.request.path_url)
+ self.assertEqual(expected_params, urlparse.parse_qs(url_params))
def test_get_collection_links_doesnt_create_next_if_no_limit(self):
self.setUpGetCollectionLinks()
@@ -62,9 +64,12 @@ class TestViewsCommon(common.HeatTestCase):
self.request.params = {'limit': '2', 'marker': 'some_marker'}
links = views_common.get_collection_links(self.request, self.items)
- expected = 'http://example.com/fake/path?marker=id2&limit=2'
+ expected_params = {'marker': ['id2'], 'limit': ['2']}
next_link = filter(lambda link: link['rel'] == 'next', links).pop()
- self.assertEqual(expected, next_link['href'])
+ self.assertEqual('next', next_link['rel'])
+ url_path, url_params = next_link['href'].split('?', 1)
+ self.assertEqual(url_path, self.request.path_url)
+ self.assertEqual(expected_params, urlparse.parse_qs(url_params))
def test_get_collection_links_does_not_overwrite_other_params(self):
self.setUpGetCollectionLinks()
diff --git a/heat/tests/aws/test_loadbalancer.py b/heat/tests/aws/test_loadbalancer.py
index 29447c0082..3bd951497d 100644
--- a/heat/tests/aws/test_loadbalancer.py
+++ b/heat/tests/aws/test_loadbalancer.py
@@ -88,7 +88,8 @@ class LoadBalancerTest(common.HeatTestCase):
lb_defn = s.t.resource_definitions(s)[resource_name]
rsrc = lb.LoadBalancer(resource_name, lb_defn, s)
- nova.NovaClientPlugin._create = mock.Mock(return_value=self.fc)
+ self.patchobject(nova.NovaClientPlugin, '_create',
+ return_value=self.fc)
initial_md = {'AWS::CloudFormation::Init':
{'config':
diff --git a/heat/tests/ceilometer/test_ceilometer_alarm.py b/heat/tests/ceilometer/test_ceilometer_alarm.py
index 2bb8946a2a..55661e3474 100644
--- a/heat/tests/ceilometer/test_ceilometer_alarm.py
+++ b/heat/tests/ceilometer/test_ceilometer_alarm.py
@@ -198,7 +198,7 @@ class CeilometerAlarmTest(common.HeatTestCase):
if 'matching_metadata' in al:
del al['matching_metadata']
if query:
- rule['query'] = query
+ rule['query'] = mox.SameElementsAs(query)
al['threshold_rule'] = rule
al['type'] = 'threshold'
self.m.StubOutWithMock(self.fa.alarms, 'create')
@@ -396,8 +396,9 @@ class CeilometerAlarmTest(common.HeatTestCase):
self.m.VerifyAll()
def test_mem_alarm_high_not_correct_string_parameters(self):
- snippet = template_format.parse(not_string_alarm_template)
+ orig_snippet = template_format.parse(not_string_alarm_template)
for p in ('period', 'evaluation_periods'):
+ snippet = copy.deepcopy(orig_snippet)
snippet['Resources']['MEMAlarmHigh']['Properties'][p] = '60a'
stack = utils.parse_stack(snippet)
@@ -411,8 +412,9 @@ class CeilometerAlarmTest(common.HeatTestCase):
"Value '60a' is not an integer" % p, six.text_type(error))
def test_mem_alarm_high_not_integer_parameters(self):
- snippet = template_format.parse(not_string_alarm_template)
+ orig_snippet = template_format.parse(not_string_alarm_template)
for p in ('period', 'evaluation_periods'):
+ snippet = copy.deepcopy(orig_snippet)
snippet['Resources']['MEMAlarmHigh']['Properties'][p] = [60]
stack = utils.parse_stack(snippet)
diff --git a/heat/tests/clients/test_nova_client.py b/heat/tests/clients/test_nova_client.py
index 260dfd3b20..24ef89258d 100644
--- a/heat/tests/clients/test_nova_client.py
+++ b/heat/tests/clients/test_nova_client.py
@@ -374,7 +374,12 @@ class NovaClientPluginMetadataTests(NovaClientPluginTestCase):
self.assertEqual(expected, self.nova_plugin.meta_serialize(original))
def test_serialize_dict(self):
- original = {'test_key': {'a': 'b', 'c': 'd'}}
+ original = collections.OrderedDict([
+ ('test_key', collections.OrderedDict([
+ ('a', 'b'),
+ ('c', 'd'),
+ ]))
+ ])
expected = {'test_key': '{"a": "b", "c": "d"}'}
actual = self.nova_plugin.meta_serialize(original)
self.assertEqual(json.loads(expected['test_key']),
diff --git a/heat/tests/engine/test_software_config.py b/heat/tests/engine/test_software_config.py
index 807f317665..0a681fe6cd 100644
--- a/heat/tests/engine/test_software_config.py
+++ b/heat/tests/engine/test_software_config.py
@@ -85,6 +85,11 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
return self.engine.create_software_config(
self.ctx, group, name, config, inputs, outputs, options)
+ def assert_status_reason(self, expected, actual):
+ expected_dict = dict((i.split(' : ') for i in expected.split(', ')))
+ actual_dict = dict((i.split(' : ') for i in actual.split(', ')))
+ self.assertEqual(expected_dict, actual_dict)
+
def test_list_software_configs(self):
config = self._create_software_config()
config_id = config['id']
@@ -362,7 +367,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
sd = software_deployment_object.SoftwareDeployment.get_by_id(
self.ctx, deployment_id)
self.assertEqual('FAILED', sd.status)
- self.assertEqual(
+ self.assert_status_reason(
('deploy_status_code : Deployment exited with non-zero '
'status code: -1'),
sd.status_reason)
@@ -394,7 +399,7 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
sd = software_deployment_object.SoftwareDeployment.get_by_id(
self.ctx, deployment_id)
self.assertEqual('FAILED', sd.status)
- self.assertEqual(
+ self.assert_status_reason(
('foo : bar, deploy_status_code : Deployment exited with '
'non-zero status code: -1'),
sd.status_reason)
diff --git a/heat/tests/generic_resource.py b/heat/tests/generic_resource.py
index 254b809044..6303d67edf 100644
--- a/heat/tests/generic_resource.py
+++ b/heat/tests/generic_resource.py
@@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
from oslo_log import log as logging
import six
@@ -31,8 +32,9 @@ class GenericResource(resource.Resource):
Dummy resource for use in tests
'''
properties_schema = {}
- attributes_schema = {'foo': attributes.Schema('A generic attribute'),
- 'Foo': attributes.Schema('Another generic attribute')}
+ attributes_schema = collections.OrderedDict([
+ ('foo', attributes.Schema('A generic attribute')),
+ ('Foo', attributes.Schema('Another generic attribute'))])
@classmethod
def is_service_available(cls, context):
diff --git a/heat/tests/openstack/test_waitcondition.py b/heat/tests/openstack/test_waitcondition.py
index 8fe152543f..5897f14296 100644
--- a/heat/tests/openstack/test_waitcondition.py
+++ b/heat/tests/openstack/test_waitcondition.py
@@ -214,7 +214,8 @@ class HeatWaitConditionTest(common.HeatTestCase):
'status': 'SUCCESS', 'id': '456'}
ret = handle.handle_signal(details=test_metadata)
wc_att = rsrc.FnGetAtt('data')
- self.assertEqual(u'{"123": "foo", "456": "dog"}', wc_att)
+ self.assertEqual(json.loads(u'{"123": "foo", "456": "dog"}'),
+ json.loads(wc_att))
self.assertEqual('status:SUCCESS reason:cat', ret)
self.m.VerifyAll()
diff --git a/heat/tests/test_common_serializers.py b/heat/tests/test_common_serializers.py
index eadbb7e253..5bbe623bd4 100644
--- a/heat/tests/test_common_serializers.py
+++ b/heat/tests/test_common_serializers.py
@@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
import datetime
import webob
@@ -37,13 +38,21 @@ class JSONResponseSerializerTest(common.HeatTestCase):
self.assertEqual(expected, actual)
def test_to_json_with_more_deep_format(self):
- fixture = {"is_public": True, "name": [{"name1": "test"}]}
+ fixture = collections.OrderedDict([
+ ('is_public', True),
+ ('name', [collections.OrderedDict([
+ ('name1', 'test'),
+ ])])
+ ])
expected = '{"is_public": true, "name": [{"name1": "test"}]}'
actual = serializers.JSONResponseSerializer().to_json(fixture)
self.assertEqual(expected, actual)
def test_to_json_with_objects(self):
- fixture = {"is_public": True, "value": complex(1, 2)}
+ fixture = collections.OrderedDict([
+ ('is_public', True),
+ ('value', complex(1, 2)),
+ ])
expected = '{"is_public": true, "value": "(1+2j)"}'
actual = serializers.JSONResponseSerializer().to_json(fixture)
self.assertEqual(expected, actual)
@@ -83,8 +92,14 @@ class XMLResponseSerializerTest(common.HeatTestCase):
def test_to_xml_with_more_deep_format(self):
# Note we expect tree traversal from one root key, which is compatible
# with the AWS format responses we need to serialize
- fixture = {"aresponse":
- {"is_public": True, "name": [{"name1": "test"}]}}
+ fixture = collections.OrderedDict([
+ ('aresponse', collections.OrderedDict([
+ ('is_public', True),
+ ('name', [collections.OrderedDict([
+ ('name1', 'test'),
+ ])])
+ ]))
+ ])
expected = ('True'
'test'
'')
@@ -94,10 +109,13 @@ class XMLResponseSerializerTest(common.HeatTestCase):
def test_to_xml_with_json_only_keys(self):
# Certain keys are excluded from serialization because CFN
# format demands a json blob in the XML body
- fixture = {"aresponse":
- {"is_public": True,
- "TemplateBody": {"name1": "test"},
- "Metadata": {"name2": "test2"}}}
+ fixture = collections.OrderedDict([
+ ('aresponse', collections.OrderedDict([
+ ('is_public', True),
+ ('TemplateBody', {"name1": "test"}),
+ ('Metadata', {"name2": "test2"}),
+ ]))
+ ])
expected = ('True'
'{"name1": "test"}'
'{"name2": "test2"}')
diff --git a/heat/tests/test_metadata_refresh.py b/heat/tests/test_metadata_refresh.py
index 1e2dfcc272..ce3d5d1fc1 100644
--- a/heat/tests/test_metadata_refresh.py
+++ b/heat/tests/test_metadata_refresh.py
@@ -13,6 +13,7 @@
import mock
import mox
+from oslo_serialization import jsonutils
from heat.common import identifier
from heat.common import template_format
@@ -286,12 +287,13 @@ class WaitCondMetadataUpdateTest(common.HeatTestCase):
update_metadata('456', 'blarg', 'wibble')
- self.assertEqual('{"123": "foo", "456": "blarg"}',
- watch.FnGetAtt('Data'))
+ self.assertEqual({'123': 'foo', '456': 'blarg'},
+ jsonutils.loads(watch.FnGetAtt('Data')))
self.assertEqual('{"123": "foo"}',
inst.metadata_get()['test'])
- self.assertEqual('{"123": "foo", "456": "blarg"}',
- inst.metadata_get(refresh=True)['test'])
+ self.assertEqual(
+ {'123': 'foo', '456': 'blarg'},
+ jsonutils.loads(inst.metadata_get(refresh=True)['test']))
self.m.VerifyAll()
diff --git a/heat/tests/test_parameters.py b/heat/tests/test_parameters.py
index 07b0904131..125496f288 100644
--- a/heat/tests/test_parameters.py
+++ b/heat/tests/test_parameters.py
@@ -75,7 +75,10 @@ class ParameterTestCommon(common.HeatTestCase):
def test_param_to_str(self):
p = new_parameter('p', {'Type': self.p_type}, self.value)
- self.assertEqual(self.expected, str(p))
+ if self.p_type == 'Json':
+ self.assertEqual(json.loads(self.expected), json.loads(str(p)))
+ else:
+ self.assertEqual(self.expected, str(p))
def test_default_no_override(self):
p = new_parameter('defaulted', {'Type': self.p_type,
@@ -137,7 +140,10 @@ class ParameterTestCommon(common.HeatTestCase):
'NoEcho': 'false'},
self.value)
self.assertFalse(p.hidden())
- self.assertEqual(self.expected, str(p))
+ if self.p_type == 'Json':
+ self.assertEqual(json.loads(self.expected), json.loads(str(p)))
+ else:
+ self.assertEqual(self.expected, str(p))
def test_default_empty(self):
p = new_parameter('defaulted', {'Type': self.p_type,
diff --git a/heat/tests/test_provider_template.py b/heat/tests/test_provider_template.py
index eddb67519d..d6f1017eab 100644
--- a/heat/tests/test_provider_template.py
+++ b/heat/tests/test_provider_template.py
@@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
import json
import os
import uuid
@@ -140,8 +141,13 @@ class ProviderTemplateTest(common.HeatTestCase):
prop_vals = {
"Foo": "Bar",
"AList": ["one", "two", "three"],
- "MemList": [{"key": "name", "value": "three"},
- {"key": "name", "value": "four"}],
+ "MemList": [collections.OrderedDict([
+ ('key', 'name'),
+ ('value', 'three'),
+ ]), collections.OrderedDict([
+ ('key', 'name'),
+ ('value', 'four'),
+ ])],
"ListEmpty": [],
"ANum": 5,
"AMap": map_prop_val,
@@ -165,7 +171,8 @@ class ProviderTemplateTest(common.HeatTestCase):
'.member.0.value=three,'
'.member.1.key=name,'
'.member.1.value=four')
- self.assertEqual(mem_exp, converted_params.get("MemList"))
+ self.assertEqual(sorted(mem_exp.split(',')),
+ sorted(converted_params.get("MemList").split(',')))
# verify Number conversion
self.assertEqual(5, converted_params.get("ANum"))
# verify Map conversion
diff --git a/heat/tests/test_signal.py b/heat/tests/test_signal.py
index 4082899cd8..52f374ecdd 100644
--- a/heat/tests/test_signal.py
+++ b/heat/tests/test_signal.py
@@ -17,6 +17,7 @@ import uuid
from keystoneclient import exceptions as kc_exceptions
import mox
import six
+from six.moves.urllib import parse as urlparse
from heat.common import exception
from heat.common import template_format
@@ -176,19 +177,25 @@ class SignalTest(common.HeatTestCase):
rsrc.created_time = created_time
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
- expected_url = "".join([
+ # url parameters come in unexpected order, so the conversion has to be
+ # done for comparison
+ expected_url_path = "".join([
'http://server.test:8000/v1/signal/',
'arn%3Aopenstack%3Aheat%3A%3Atest_tenant%3Astacks%2F',
'test_stack%2FSTACKABCD1234%2Fresources%2F',
- 'signal_handler?',
- 'Timestamp=2012-11-29T13%3A49%3A37Z&',
- 'SignatureMethod=HmacSHA256&',
- 'AWSAccessKeyId=4567&',
- 'SignatureVersion=2&',
- 'Signature=',
- 'VW4NyvRO4WhQdsQ4rxl5JMUr0AlefHN6OLsRz9oZyls%3D'])
+ 'signal_handler'])
+ expected_url_params = {
+ 'Timestamp': ['2012-11-29T13:49:37Z'],
+ 'SignatureMethod': ['HmacSHA256'],
+ 'AWSAccessKeyId': ['4567'],
+ 'SignatureVersion': ['2'],
+ 'Signature': ['VW4NyvRO4WhQdsQ4rxl5JMUr0AlefHN6OLsRz9oZyls=']}
- self.assertEqual(expected_url, rsrc.FnGetAtt('AlarmUrl'))
+ url = rsrc.FnGetAtt('AlarmUrl')
+ url_path, url_params = url.split('?', 1)
+ url_params = urlparse.parse_qs(url_params)
+ self.assertEqual(expected_url_path, url_path)
+ self.assertEqual(expected_url_params, url_params)
self.m.VerifyAll()
def test_FnGetAtt_Alarm_Url_is_cached(self):
diff --git a/heat/tests/test_stack_resource.py b/heat/tests/test_stack_resource.py
index c04d021445..3a1becaca6 100644
--- a/heat/tests/test_stack_resource.py
+++ b/heat/tests/test_stack_resource.py
@@ -17,6 +17,7 @@ import uuid
import mock
from oslo_config import cfg
from oslo_messaging import exceptions as msg_exceptions
+from oslo_serialization import jsonutils
import six
import testtools
@@ -156,11 +157,24 @@ class StackResourceBaseTest(common.HeatTestCase):
class StackResourceTest(StackResourceBaseTest):
+
def setUp(self):
super(StackResourceTest, self).setUp()
self.templ = template_format.parse(param_template)
self.simple_template = template_format.parse(simple_template)
+ # to get same json string from a dict for comparison,
+ # make sort_keys True
+ orig_dumps = jsonutils.dumps
+
+ def sorted_dumps(*args, **kwargs):
+ kwargs.setdefault('sort_keys', True)
+ return orig_dumps(*args, **kwargs)
+ patched_dumps = mock.patch(
+ 'oslo_serialization.jsonutils.dumps', sorted_dumps)
+ patched_dumps.start()
+ self.addCleanup(lambda: patched_dumps.stop())
+
def test_child_template_defaults_to_not_implemented(self):
self.assertRaises(NotImplementedError,
self.parent_resource.child_template)
@@ -188,8 +202,8 @@ class StackResourceTest(StackResourceBaseTest):
sig1, sig2 = self.parent_resource.implementation_signature()
self.assertEqual('7b0eaabb5b82b9e90804d42e0bb739035588cb797'
'82427770646686ca2235028', sig1)
- self.assertEqual('5a58b34cc3dd7f4e11fa35b63daad7b6b3aaa1744'
- '19eb1c42b75d102bdda5fc9', sig2)
+ self.assertEqual('8fa647d036b8f36909386e1e1004539dfae7a8e88'
+ 'c24aac0d85399e881421301', sig2)
self.parent_stack.t.files["foo"] = "bar"
sig1a, sig2a = self.parent_resource.implementation_signature()
self.assertEqual(sig1, sig1a)
diff --git a/heat/tests/utils.py b/heat/tests/utils.py
index 182daaf2b9..3126aa11cf 100644
--- a/heat/tests/utils.py
+++ b/heat/tests/utils.py
@@ -15,8 +15,10 @@ import random
import string
import uuid
+import mox
from oslo_config import cfg
from oslo_db import options
+from oslo_serialization import jsonutils
import sqlalchemy
from heat.common import context
@@ -143,3 +145,32 @@ class PhysName(object):
def __repr__(self):
return self._physname
+
+
+def recursive_sort(obj):
+ """Recursively sort list in iterables for comparison."""
+ if isinstance(obj, dict):
+ for v in obj.values():
+ recursive_sort(v)
+ elif isinstance(obj, list):
+ obj.sort()
+ for i in obj:
+ recursive_sort(i)
+ return obj
+
+
+class JsonEquals(mox.Comparator):
+ """Comparison class used to check if two json strings equal.
+
+ If a dict is dumped to json, the order is undecided, so load the string
+ back to an object for comparison
+ """
+
+ def __init__(self, other_json):
+ self.other_json = other_json
+
+ def equals(self, rhs):
+ return jsonutils.loads(self.other_json) == jsonutils.loads(rhs)
+
+ def __repr__(self):
+ return "" % self.other_json
diff --git a/tox.ini b/tox.ini
index 2d1c07ea12..0eef4fd407 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,10 +4,7 @@ minversion = 1.6
skipsdist = True
[testenv]
-# Note the hash seed is set to 0 until heat can be tested with a
-# random hash seed successfully.
setenv = VIRTUAL_ENV={envdir}
- PYTHONHASHSEED=0
usedevelop = True
install_command = pip install {opts} {packages}
deps = -r{toxinidir}/requirements.txt