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:
Sean Dague
2015-12-10 08:47:07 -05:00
parent e31f9a9811
commit ede70a1973
13 changed files with 109 additions and 52 deletions

View File

@@ -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)

View File

@@ -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):

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 = {

View File

@@ -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):

View File

@@ -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):

View File

@@ -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):

View File

@@ -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."""

View File

@@ -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

View File

@@ -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'})]

View File

@@ -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)

View File

@@ -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