# Copyright 2015 HPE, Inc. # # 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 copy import mock import testtools from nova import test from nova.tests.functional import api_samples_test_base class TestCompareResult(test.NoDBTestCase): """Provide test coverage for result comparison logic in functional tests. _compare_result two types of comparisons, template data and sample data. Template data means the response is checked against a regex that is referenced by the template name. The template name is specified in the format %(name) Sample data is a normal value comparison. """ def getApiSampleTestBaseHelper(self): """Build an instance without running any unwanted test methods""" # NOTE(auggy): TestCase takes a "test" method name to run in __init__ # calling this way prevents additional test methods from running ast_instance = api_samples_test_base.ApiSampleTestBase('setUp') # required by ApiSampleTestBase ast_instance.api_major_version = 'v2' ast_instance._use_project_id = 'True' # automagically create magic methods usually handled by test classes ast_instance.compute = mock.MagicMock() ast_instance.subs = ast_instance._get_regexes() return ast_instance def setUp(self): super(TestCompareResult, self).setUp() self.ast = self.getApiSampleTestBaseHelper() def test_bare_strings_match(self): """compare 2 bare strings that match""" sample_data = u'foo' response_data = u'foo' result = self.ast._compare_result( expected=sample_data, result=response_data, result_str="Test") # NOTE(auggy): _compare_result will not return a matched value in the # case of bare strings. If they don't match it will throw an exception, # otherwise it returns "None". self.assertEqual( expected=None, observed=result, message='Check _compare_result of 2 bare strings') def test_bare_strings_no_match(self): """check 2 bare strings that don't match""" sample_data = u'foo' response_data = u'bar' with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=sample_data, result=response_data, result_str="Test") def test_template_strings_match(self): """compare 2 template strings (contain %) that match""" template_data = u'%(id)s' response_data = u'858f295a-8543-45fa-804a-08f8356d616d' result = self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") self.assertEqual( expected=response_data, observed=result, message='Check _compare_result of 2 template strings') def test_template_strings_no_match(self): """check 2 template strings (contain %) that don't match""" template_data = u'%(id)s' response_data = u'$58f295a-8543-45fa-804a-08f8356d616d' with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") # TODO(auggy): _compare_result needs a consistent return value # In some cases it returns the value if it matched, in others it returns # None. In all cases, it throws an exception if there's no match. def test_bare_int_match(self): """check 2 bare ints that match""" sample_data = 42 response_data = 42 result = self.ast._compare_result( expected=sample_data, result=response_data, result_str="Test") self.assertEqual( expected=None, observed=result, message='Check _compare_result of 2 bare ints') def test_bare_int_no_match(self): """check 2 bare ints that don't match""" sample_data = 42 response_data = 43 with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=sample_data, result=response_data, result_str="Test") # TODO(auggy): _compare_result needs a consistent return value def test_template_int_match(self): """check template int against string containing digits""" template_data = u'%(int)s' response_data = u'42' result = self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") self.assertEqual( expected=None, observed=result, message='Check _compare_result of template ints') def test_template_int_no_match(self): """check template int against a string containing no digits""" template_data = u'%(int)s' response_data = u'foo' with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") def test_template_int_value(self): """check an int value of a template int throws exception""" # template_data = u'%(int_test)' # response_data = 42 # use an int instead of a string as the subs value local_subs = copy.deepcopy(self.ast.subs) local_subs.update({'int_test': 42}) with testtools.ExpectedException(TypeError): self.ast.subs = local_subs # TODO(auggy): _compare_result needs a consistent return value def test_dict_match(self): """check 2 matching dictionaries""" template_data = { u'server': { u'id': u'%(id)s', u'adminPass': u'%(password)s' } } response_data = { u'server': { u'id': u'858f295a-8543-45fa-804a-08f8356d616d', u'adminPass': u'4ZQ3bb6WYbC2'} } result = self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") self.assertEqual( expected=u'858f295a-8543-45fa-804a-08f8356d616d', observed=result, message='Check _compare_result of 2 dictionaries') def test_dict_no_match_value(self): """check 2 dictionaries where one has a different value""" sample_data = { u'server': { u'id': u'858f295a-8543-45fa-804a-08f8356d616d', u'adminPass': u'foo' } } response_data = { u'server': { u'id': u'858f295a-8543-45fa-804a-08f8356d616d', u'adminPass': u'4ZQ3bb6WYbC2'} } with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=sample_data, result=response_data, result_str="Test") def test_dict_no_match_extra_key(self): """check 2 dictionaries where one has an extra key""" template_data = { u'server': { u'id': u'%(id)s', u'adminPass': u'%(password)s', u'foo': u'foo' } } response_data = { u'server': { u'id': u'858f295a-8543-45fa-804a-08f8356d616d', u'adminPass': u'4ZQ3bb6WYbC2'} } with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") def test_dict_result_type_mismatch(self): """check expected is a dictionary and result is not a dictionary""" template_data = { u'server': { u'id': u'%(id)s', u'adminPass': u'%(password)s', } } response_data = u'foo' with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") # TODO(auggy): _compare_result needs a consistent return value def test_list_match(self): """check 2 matching lists""" template_data = { u'links': [ { u'href': u'%(versioned_compute_endpoint)s/server/%(uuid)s', u'rel': u'self' }, { u'href': u'%(compute_endpoint)s/servers/%(uuid)s', u'rel': u'bookmark' } ] } response_data = { u'links': [ { u'href': (u'http://openstack.example.com/v2/%s/server/' '858f295a-8543-45fa-804a-08f8356d616d' % api_samples_test_base.PROJECT_ID ), u'rel': u'self' }, { u'href': (u'http://openstack.example.com/%s/servers/' '858f295a-8543-45fa-804a-08f8356d616d' % api_samples_test_base.PROJECT_ID ), u'rel': u'bookmark' } ] } result = self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") self.assertEqual( expected=None, observed=result, message='Check _compare_result of 2 lists') def test_list_match_extra_item_result(self): """check extra list items in result """ template_data = { u'links': [ { u'href': u'%(versioned_compute_endpoint)s/server/%(uuid)s', u'rel': u'self' }, { u'href': u'%(compute_endpoint)s/servers/%(uuid)s', u'rel': u'bookmark' } ] } response_data = { u'links': [ { u'href': (u'http://openstack.example.com/v2/openstack/server/' '858f295a-8543-45fa-804a-08f8356d616d'), u'rel': u'self' }, { u'href': (u'http://openstack.example.com/openstack/servers/' '858f295a-8543-45fa-804a-08f8356d616d'), u'rel': u'bookmark' }, u'foo' ] } with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") def test_list_match_extra_item_template(self): """check extra list items in template """ template_data = { u'links': [ { u'href': u'%(versioned_compute_endpoint)s/server/%(uuid)s', u'rel': u'self' }, { u'href': u'%(compute_endpoint)s/servers/%(uuid)s', u'rel': u'bookmark' }, u'foo' # extra field ] } response_data = { u'links': [ { u'href': (u'http://openstack.example.com/v2/openstack/server/' '858f295a-8543-45fa-804a-08f8356d616d'), u'rel': u'self' }, { u'href': (u'http://openstack.example.com/openstack/servers/' '858f295a-8543-45fa-804a-08f8356d616d'), u'rel': u'bookmark' } ] } with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") def test_list_no_match(self): """check 2 matching lists""" template_data = { u'things': [ { u'foo': u'bar', u'baz': 0 }, { u'foo': u'zod', u'baz': 1 } ] } response_data = { u'things': [ { u'foo': u'bar', u'baz': u'0' }, { u'foo': u'zod', u'baz': 1 } ] } # TODO(auggy): This error returns "extra list items" # it should show the item/s in the list that didn't match with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=template_data, result=response_data, result_str="Test") def test_none_match(self): """check that None matches""" sample_data = None response_data = None result = self.ast._compare_result( expected=sample_data, result=response_data, result_str="Test") # NOTE(auggy): _compare_result will not return a matched value in the # case of bare strings. If they don't match it will throw an exception, # otherwise it returns "None". self.assertEqual( expected=None, observed=result, message='Check _compare_result of None') def test_none_no_match(self): """check expected none and non-None response don't match""" sample_data = None response_data = u'bar' with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=sample_data, result=response_data, result_str="Test") def test_none_result_no_match(self): """check result none and expected non-None response don't match""" sample_data = u'foo' response_data = None with testtools.ExpectedException(api_samples_test_base.NoMatch): self.ast._compare_result( expected=sample_data, result=response_data, result_str="Test") def test_template_no_subs_key(self): """check an int value of a template int throws exception""" template_data = u'%(foo)' response_data = 'bar' with testtools.ExpectedException(KeyError): self.ast._compare_result( expected=template_data, result=response_data, result_str="Test")