Use testscenarios to set attributes directly
testscenarios was previously used to set an intermediary symbol, which then set additional attributes. This got really complicated to figure out what scenarios were really doing, and how to add more (or bypass them in tests). This clarifies that usage, unwinds the testscenarios simplifying what gets set up. It also starts making calls to API v2.1 on the v2.1 url. This is supported with existing API samples docs with a mechanism to update links if they exist in the docs. Change-Id: I9affc046300295cdf3e284ccc736019ccaffb9f2
This commit is contained in:
@@ -17,9 +17,7 @@ import os
|
||||
from oslo_config import cfg
|
||||
import testscenarios
|
||||
|
||||
from nova.api import openstack
|
||||
from nova.api.openstack import API_V21_CORE_EXTENSIONS # noqa
|
||||
from nova.api.openstack import compute
|
||||
from nova import test
|
||||
from nova.tests.functional import api_paste_fixture
|
||||
from nova.tests.functional import api_samples_test_base
|
||||
@@ -28,15 +26,64 @@ from nova.tests.unit import fake_utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
# API samples heavily uses testscenarios. This allows us to use the
|
||||
# same tests, with slight variations in configuration to ensure our
|
||||
# various ways of calling the API are compatible. Testscenarios works
|
||||
# through the class level ``scenarios`` variable. It is an array of
|
||||
# tuples where the first value in each tuple is an arbitrary name for
|
||||
# the scenario (should be unique), and the second item is a dictionary
|
||||
# of attributes to change in the class for the test.
|
||||
#
|
||||
# By default we're running scenarios for 3 situations
|
||||
#
|
||||
# - Hitting the default /v2 endpoint
|
||||
#
|
||||
# - Hitting the default /v2.1 endpoint
|
||||
#
|
||||
# - Hitting the /v2 but fixing the paste pipeline so that it uses the
|
||||
# legacy v2 code. This requires a fixture.
|
||||
#
|
||||
# Things we need to set:
|
||||
#
|
||||
# - _api_version - what version of the API we should be hitting
|
||||
#
|
||||
# - request_api_version - what API microversion should be used
|
||||
#
|
||||
# - _additional_fixtures - any additional fixtures need
|
||||
#
|
||||
# - _legacy_v2_code - True/False if we are using the legacy v2 code
|
||||
# stack. Sadly, a few tests really care about this.
|
||||
#
|
||||
# NOTE(sdague): if you want to build a test that only tests specific
|
||||
# microversions, then replace the ``scenarios`` class variable in that
|
||||
# test class with something like:
|
||||
#
|
||||
# [("v2_11", {'_api_version': 'v2.1', 'request_api_version', '2.11'})]
|
||||
|
||||
|
||||
class ApiSampleTestBaseV21(testscenarios.WithScenarios,
|
||||
api_samples_test_base.ApiSampleTestBase):
|
||||
_api_version = 'v2'
|
||||
# any additional fixtures needed for this scenario
|
||||
_additional_fixtures = []
|
||||
sample_dir = None
|
||||
extra_extensions_to_load = None
|
||||
scenarios = [('v2', {'_test': 'v2'}),
|
||||
('v2_1', {'_test': 'v2.1'}),
|
||||
('v2_1_compatible', {'_test': 'v2.1_compatible'})]
|
||||
_legacy_v2_code = False
|
||||
|
||||
scenarios = [
|
||||
# test v2 with the v2.1 compatibility stack
|
||||
('v2', {
|
||||
'_api_version': 'v2'}),
|
||||
# test v2.1 base microversion
|
||||
('v2_1', {
|
||||
'_api_version': 'v2.1'}),
|
||||
# test v2 with the v2 legacy code
|
||||
('v2legacy', {
|
||||
'_api_version': 'v2',
|
||||
'_legacy_v2_code': True,
|
||||
'_additional_fixtures': [
|
||||
api_paste_fixture.ApiPasteLegacyV2Fixture]})
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
self.flags(use_ipv6=False,
|
||||
@@ -55,24 +102,19 @@ class ApiSampleTestBaseV21(testscenarios.WithScenarios,
|
||||
|
||||
CONF.set_override('extensions_whitelist', whitelist,
|
||||
'osapi_v21')
|
||||
expected_middleware = []
|
||||
if (not hasattr(self, '_test') or (self._test == 'v2.1')):
|
||||
# NOTE(gmann): we should run v21 tests on /v2.1 but then we need
|
||||
# two sets of sample files as api version (v2 or v2.1) is being
|
||||
# added in response's link/namespace etc
|
||||
# override /v2 in compatibility mode with v2.1
|
||||
self.useFixture(api_paste_fixture.ApiPasteV21Fixture())
|
||||
expected_middleware = [compute.APIRouterV21]
|
||||
elif self._test == 'v2.1_compatible':
|
||||
expected_middleware = [openstack.LegacyV2CompatibleWrapper,
|
||||
compute.APIRouterV21]
|
||||
elif (self._test == 'v2' and self._api_version == 'v2'):
|
||||
# override /v2 in compatibility mode with v2 legacy
|
||||
self.useFixture(api_paste_fixture.ApiPasteLegacyV2Fixture())
|
||||
|
||||
# load any additional fixtures specified by the scenario
|
||||
for fix in self._additional_fixtures:
|
||||
self.useFixture(fix())
|
||||
|
||||
# super class call is delayed here so that we have the right
|
||||
# paste and conf before loading all the services, as we can't
|
||||
# change these later.
|
||||
super(ApiSampleTestBaseV21, self).setUp()
|
||||
|
||||
self.useFixture(test.SampleNetworks(host=self.network.host))
|
||||
fake_network.stub_compute_with_ips(self.stubs)
|
||||
fake_utils.stub_out_utils_spawn_n(self.stubs)
|
||||
|
||||
# this is used to generate sample docs
|
||||
self.generate_samples = os.getenv('GENERATE_SAMPLES') is not None
|
||||
if expected_middleware:
|
||||
self._check_api_endpoint('/v2', expected_middleware)
|
||||
|
||||
@@ -39,8 +39,8 @@ class AccessIPsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
||||
return f
|
||||
|
||||
def _servers_post(self, subs):
|
||||
response = self._do_post('servers', 'server-post-req', subs)
|
||||
subs.update(self._get_regexes())
|
||||
response = self._do_post('servers', 'server-post-req', subs)
|
||||
return self._verify_response('server-post-resp', subs, response, 202)
|
||||
|
||||
def test_servers_post(self):
|
||||
|
||||
@@ -38,11 +38,15 @@ class ExtensionInfoAllSamplesJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
||||
soft_auth.side_effect = fake_soft_extension_authorizer
|
||||
response = self._do_get('extensions')
|
||||
subs = self._get_regexes()
|
||||
# The full extension list is one of the places that things are
|
||||
# different between the API versions and the legacy vs. new
|
||||
# stack. We default to the v2.1 case.
|
||||
template = 'extensions-list-resp'
|
||||
if self._test == 'v2':
|
||||
template = 'extensions-list-resp-v2'
|
||||
if self._test == 'v2.1_compatible':
|
||||
if self._api_version == 'v2':
|
||||
template = 'extensions-list-resp-v21-compatible'
|
||||
if self._api_version == 'v2' and self._legacy_v2_code:
|
||||
template = 'extensions-list-resp-v2'
|
||||
|
||||
self._verify_response(template, subs, response, 200)
|
||||
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ class FixedIpV24Test(FixedIpTest):
|
||||
# NOTE(gmann): microversion tests do not need to run for v2 API
|
||||
# so defining scenarios only for v2.4 which will run the original tests
|
||||
# by appending '(v2_4)' in test_id.
|
||||
scenarios = [('v2_4', {})]
|
||||
scenarios = [('v2_4', {'_api_version': 'v2.1'})]
|
||||
|
||||
def test_get_fixed_ip(self):
|
||||
self._test_get_fixed_ip(reserved=False)
|
||||
|
||||
@@ -115,7 +115,7 @@ class KeyPairsV22SampleJsonTest(KeyPairsSampleJsonTest):
|
||||
# NOTE(gmann): microversion tests do not need to run for v2 API
|
||||
# so defining scenarios only for v2.2 which will run the original tests
|
||||
# by appending '(v2_2)' in test_id.
|
||||
scenarios = [('v2_2', {})]
|
||||
scenarios = [('v2_2', {'_api_version': 'v2.1'})]
|
||||
|
||||
def test_keypairs_post(self):
|
||||
# NOTE(claudiub): overrides the method with the same name in
|
||||
@@ -174,7 +174,7 @@ class KeyPairsV210SampleJsonTest(KeyPairsSampleJsonTest):
|
||||
request_api_version = '2.10'
|
||||
expected_post_status_code = 201
|
||||
expected_delete_status_code = 204
|
||||
scenarios = [('v2_10', {})]
|
||||
scenarios = [('v2_10', {'_api_version': 'v2.1'})]
|
||||
|
||||
def test_keypair_create_for_user(self):
|
||||
subs = {
|
||||
|
||||
@@ -31,7 +31,7 @@ class LimitsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
||||
# NOTE(gmann): We have to separate the template files between V2
|
||||
# and V2.1 as the response are different.
|
||||
self.template = 'limit-get-resp'
|
||||
if(self._test == "v2"):
|
||||
if self._legacy_v2_code:
|
||||
self.template = 'v2-limit-get-resp'
|
||||
|
||||
def _get_flags(self):
|
||||
|
||||
@@ -89,7 +89,7 @@ class ConsolesV26SampleJsonTests(test_servers.ServersSampleBase):
|
||||
# NOTE(gmann): microversion tests do not need to run for v2 API
|
||||
# so defining scenarios only for v2.6 which will run the original tests
|
||||
# by appending '(v2_6)' in test_id.
|
||||
scenarios = [('v2_6', {})]
|
||||
scenarios = [('v2_6', {'_api_version': 'v2.1'})]
|
||||
|
||||
def setUp(self):
|
||||
super(ConsolesV26SampleJsonTests, self).setUp()
|
||||
@@ -110,7 +110,7 @@ class ConsolesV26SampleJsonTests(test_servers.ServersSampleBase):
|
||||
class ConsolesV28SampleJsonTests(test_servers.ServersSampleBase):
|
||||
extension_name = "os-remote-consoles"
|
||||
request_api_version = '2.8'
|
||||
scenarios = [('v2_8', {})]
|
||||
scenarios = [('v2_8', {'_api_version': 'v2.1'})]
|
||||
_api_version = 'v2'
|
||||
|
||||
def setUp(self):
|
||||
|
||||
@@ -116,7 +116,7 @@ class ServersSampleJson29Test(ServersSampleJsonTest):
|
||||
# NOTE(gmann): microversion tests do not need to run for v2 API
|
||||
# so defining scenarios only for v2.9 which will run the original tests
|
||||
# by appending '(v2_9)' in test_id.
|
||||
scenarios = [('v2_9', {})]
|
||||
scenarios = [('v2_9', {'_api_version': 'v2.1'})]
|
||||
|
||||
|
||||
class ServerSortKeysJsonTests(ServersSampleBase):
|
||||
|
||||
@@ -110,8 +110,8 @@ class ServicesJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
||||
class ServicesV211JsonTest(ServicesJsonTest):
|
||||
request_api_version = '2.11'
|
||||
# NOTE(gryf): There is no need to run those tests on v2 API. Only
|
||||
# scenarios for v2_9 will be run.
|
||||
scenarios = [('v2_11', {})]
|
||||
# scenarios for v2_11 will be run.
|
||||
scenarios = [('v2_11', {'_api_version': 'v2.1'})]
|
||||
|
||||
def test_services_list(self):
|
||||
"""Return a list of all agent builds."""
|
||||
|
||||
@@ -32,18 +32,22 @@ class UsedLimitsSamplesJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
||||
# NOTE(park): We have to separate the template files between V2
|
||||
# and V2.1 as the response are different.
|
||||
self.template = 'usedlimits-get-resp'
|
||||
if(self._test == "v2"):
|
||||
if self._legacy_v2_code:
|
||||
self.template = 'v2-usedlimits-get-resp'
|
||||
|
||||
def _get_flags(self):
|
||||
f = super(UsedLimitsSamplesJsonTest, self)._get_flags()
|
||||
if self._legacy_v2_code:
|
||||
f['osapi_compute_extension'] = CONF.osapi_compute_extension[:]
|
||||
f['osapi_compute_extension'].append("nova.api.openstack.compute."
|
||||
f['osapi_compute_extension'].append(
|
||||
"nova.api.openstack.compute."
|
||||
"legacy_v2.contrib.server_group_quotas."
|
||||
"Server_group_quotas")
|
||||
f['osapi_compute_extension'].append("nova.api.openstack.compute."
|
||||
f['osapi_compute_extension'].append(
|
||||
"nova.api.openstack.compute."
|
||||
"legacy_v2.contrib.used_limits.Used_limits")
|
||||
f['osapi_compute_extension'].append("nova.api.openstack.compute."
|
||||
f['osapi_compute_extension'].append(
|
||||
"nova.api.openstack.compute."
|
||||
"legacy_v2.contrib.used_limits_for_admin."
|
||||
"Used_limits_for_admin")
|
||||
return f
|
||||
|
||||
@@ -28,8 +28,7 @@ class VirtualInterfacesJsonTest(test_servers.ServersSampleBase):
|
||||
def setUp(self):
|
||||
super(VirtualInterfacesJsonTest, self).setUp()
|
||||
self.template = 'vifs-list-resp'
|
||||
if (hasattr(self, '_test') and self._test in ('v2',
|
||||
'v2.1_compatible')):
|
||||
if self._api_version == 'v2':
|
||||
self.template = 'vifs-list-resp-v2'
|
||||
|
||||
def _get_flags(self):
|
||||
@@ -58,4 +57,4 @@ class VirtualInterfacesJsonV212Test(VirtualInterfacesJsonTest):
|
||||
# NOTE(gmann): microversion tests do not need to run for v2 API
|
||||
# so defining scenarios only for v2.12 which will run the original tests
|
||||
# by appending '(v2_12)' in test_id.
|
||||
scenarios = [('v2_12', {})]
|
||||
scenarios = [('v2_12', {'_api_version': 'v2.1'})]
|
||||
|
||||
@@ -247,6 +247,13 @@ class ApiSampleTestBase(integrated_helpers._IntegratedTestBase):
|
||||
"""
|
||||
return subs
|
||||
|
||||
def _update_links(self, sample_data):
|
||||
"""Process sample data and update version specific links."""
|
||||
url_re = self._get_host() + "/v(2|2\.1)"
|
||||
new_url = self._get_host() + "/" + self._api_version
|
||||
updated_data = re.sub(url_re, new_url, sample_data)
|
||||
return updated_data
|
||||
|
||||
def _verify_response(self, name, subs, response, exp_code):
|
||||
self.assertEqual(exp_code, response.status_code)
|
||||
response_data = response.content
|
||||
@@ -267,6 +274,7 @@ class ApiSampleTestBase(integrated_helpers._IntegratedTestBase):
|
||||
with file(self._get_sample(name,
|
||||
self.request_api_version)) as sample:
|
||||
sample_data = sample.read()
|
||||
sample_data = self._update_links(sample_data)
|
||||
|
||||
try:
|
||||
template_data = self._objectify(template_data)
|
||||
|
||||
@@ -17,7 +17,6 @@ import testscenarios
|
||||
|
||||
from nova import test
|
||||
from nova.tests import fixtures as nova_fixtures
|
||||
from nova.tests.functional import api_paste_fixture
|
||||
import nova.tests.unit.image.fake
|
||||
from nova.tests.unit import policy_fixture
|
||||
|
||||
@@ -40,15 +39,16 @@ class SecgroupsFullstack(testscenarios.WithScenarios, test.TestCase):
|
||||
# test across the scenarios listed below setting the attributres
|
||||
# in the dictionary on ``self`` for each scenario.
|
||||
scenarios = [
|
||||
('v2', {'_test': 'v2'}), # regular base scenario, test the v2 api
|
||||
('v2_1', {'_test': 'v2.1'}) # test v2.1 api on the v2 api endpoint
|
||||
('v2', {
|
||||
'_api_version': 'v2'}),
|
||||
# test v2.1 base microversion
|
||||
('v2_1', {
|
||||
'_api_version': 'v2.1'}),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(SecgroupsFullstack, self).setUp()
|
||||
self.useFixture(policy_fixture.RealPolicyFixture())
|
||||
if self._test == 'v2.1':
|
||||
self.useFixture(api_paste_fixture.ApiPasteV21Fixture())
|
||||
api_fixture = self.useFixture(nova_fixtures.OSAPIFixture())
|
||||
|
||||
self.api = api_fixture.api
|
||||
|
||||
Reference in New Issue
Block a user