Browse Source

Merge "Stop using NoAuthMiddleware in tests"

changes/62/694462/1
Zuul 3 weeks ago
parent
commit
efdc734832
10 changed files with 75 additions and 59 deletions
  1. +9
    -1
      nova/api/auth.py
  2. +29
    -6
      nova/tests/fixtures.py
  3. +15
    -41
      nova/tests/functional/api/client.py
  4. +5
    -0
      nova/tests/functional/api_sample_tests/api_sample_base.py
  5. +1
    -0
      nova/tests/functional/api_sample_tests/test_simple_tenant_usage.py
  6. +1
    -0
      nova/tests/functional/api_sample_tests/test_versions.py
  7. +7
    -1
      nova/tests/functional/integrated_helpers.py
  8. +6
    -2
      nova/tests/functional/test_middleware.py
  9. +2
    -5
      nova/tests/unit/api/openstack/test_requestlog.py
  10. +0
    -3
      nova/tests/unit/conf_fixture.py

+ 9
- 1
nova/api/auth.py View File

@@ -81,6 +81,14 @@ class InjectContext(wsgi.Middleware):
class NovaKeystoneContext(wsgi.Middleware):
"""Make a request context from keystone headers."""

@staticmethod
def _create_context(env, **kwargs):
"""Create a context from a request environ.

This exists to make test stubbing easier.
"""
return context.RequestContext.from_environ(env, **kwargs)

@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
# Build a context, including the auth_token...
@@ -101,7 +109,7 @@ class NovaKeystoneContext(wsgi.Middleware):
# middleware in newer versions.
user_auth_plugin = req.environ.get('keystone.token_auth')

ctx = context.RequestContext.from_environ(
ctx = self._create_context(
req.environ,
user_auth_plugin=user_auth_plugin,
remote_address=remote_address,

+ 29
- 6
nova/tests/fixtures.py View File

@@ -955,18 +955,21 @@ class OSAPIFixture(fixtures.Fixture):
"""

def __init__(self, api_version='v2',
project_id='6f70656e737461636b20342065766572'):
project_id='6f70656e737461636b20342065766572',
use_project_id_in_urls=False):
"""Constructor

:param api_version: the API version that we're interested in
using. Currently this expects 'v2' or 'v2.1' as possible
options.
:param project_id: the project id to use on the API.

:param use_project_id_in_urls: If True, act like the "endpoint" in the
"service catalog" has the legacy format including the project_id.
"""
super(OSAPIFixture, self).__init__()
self.api_version = api_version
self.project_id = project_id
self.use_project_id_in_urls = use_project_id_in_urls

def setUp(self):
super(OSAPIFixture, self).setUp()
@@ -982,6 +985,23 @@ class OSAPIFixture(fixtures.Fixture):
}
self.useFixture(ConfPatcher(**conf_overrides))

# Stub out authentication middleware
# TODO(efried): Use keystonemiddleware.fixtures.AuthTokenFixture
self.useFixture(fixtures.MockPatch(
'keystonemiddleware.auth_token.filter_factory',
return_value=lambda _app: _app))

# Stub out context middleware
def fake_ctx(env, **kwargs):
user_id = env['HTTP_X_AUTH_USER']
project_id = env['HTTP_X_AUTH_PROJECT_ID']
is_admin = user_id == 'admin'
return context.RequestContext(
user_id, project_id, is_admin=is_admin, **kwargs)

self.useFixture(fixtures.MonkeyPatch(
'nova.api.auth.NovaKeystoneContext._create_context', fake_ctx))

# Turn off manipulation of socket_options in TCPKeepAliveAdapter
# to keep wsgi-intercept happy. Replace it with the method
# from its superclass.
@@ -999,12 +1019,15 @@ class OSAPIFixture(fixtures.Fixture):
intercept.install_intercept()
self.addCleanup(intercept.uninstall_intercept)

self.auth_url = 'http://%(host)s:%(port)s/%(api_version)s' % ({
base_url = 'http://%(host)s:%(port)s/%(api_version)s' % ({
'host': hostname, 'port': port, 'api_version': self.api_version})
self.api = client.TestOpenStackClient('fake', 'fake', self.auth_url,
self.project_id)
if self.use_project_id_in_urls:
base_url += '/' + self.project_id

self.api = client.TestOpenStackClient(
'fake', base_url, project_id=self.project_id)
self.admin_api = client.TestOpenStackClient(
'admin', 'admin', self.auth_url, self.project_id)
'admin', base_url, project_id=self.project_id)
# Provide a way to access the wsgi application to tests using
# the fixture.
self.app = app

+ 15
- 41
nova/tests/functional/api/client.py View File

@@ -124,13 +124,10 @@ class TestOpenStackClient(object):

"""

def __init__(self, auth_user, auth_key, auth_url,
project_id=None):
def __init__(self, auth_user, base_url, project_id=None):
super(TestOpenStackClient, self).__init__()
self.auth_result = None
self.auth_user = auth_user
self.auth_key = auth_key
self.auth_url = auth_url
self.base_url = base_url
if project_id is None:
self.project_id = "6f70656e737461636b20342065766572"
else:
@@ -144,49 +141,22 @@ class TestOpenStackClient(object):
response = requests.request(method, url, data=body, headers=_headers)
return response

def _authenticate(self, retry_count=0):
if self.auth_result:
return self.auth_result

auth_url = self.auth_url
headers = {'X-Auth-User': self.auth_user,
'X-Auth-Key': self.auth_key,
'X-Auth-Project-Id': self.project_id}
response = self.request(auth_url,
headers=headers)

http_status = response.status_code
LOG.debug("%(auth_url)s => code %(http_status)s",
{'auth_url': auth_url,
'http_status': http_status})

# NOTE(cdent): This is a workaround for an issue where the placement
# API fixture may respond when a request was supposed to go to the
# compute API fixture. Retry a few times, hoping to hit the right
# fixture.
if http_status == 401:
if retry_count <= 3:
return self._authenticate(retry_count=retry_count + 1)
else:
raise OpenStackApiAuthenticationException(response=response)

self.auth_result = response.headers
return self.auth_result

def api_request(self, relative_uri, check_response_status=None,
strip_version=False, **kwargs):
auth_result = self._authenticate()

# NOTE(justinsb): httplib 'helpfully' converts headers to lower case
base_uri = auth_result['x-server-management-url']
base_uri = self.base_url
if strip_version:
# NOTE(vish): cut out version number and tenant_id
base_uri = '/'.join(base_uri.split('/', 3)[:-1])
# The base_uri is either http://%(host)s:%(port)s/%(api_version)s
# or http://%(host)s:%(port)s/%(api_version)s/%(project_id)s
# NOTE(efried): Using urlparse was not easier :)
chunked = base_uri.split('/')
base_uri = '/'.join(chunked[:3])
# Restore the project ID if present
if len(chunked) == 5:
base_uri += '/' + chunked[-1]

full_uri = '%s/%s' % (base_uri, relative_uri)

headers = kwargs.setdefault('headers', {})
headers['X-Auth-Token'] = auth_result['x-auth-token']
if ('X-OpenStack-Nova-API-Version' in headers or
'OpenStack-API-Version' in headers):
raise Exception('Microversion should be set via '
@@ -195,6 +165,10 @@ class TestOpenStackClient(object):
headers['X-OpenStack-Nova-API-Version'] = self.microversion
headers['OpenStack-API-Version'] = 'compute %s' % self.microversion

headers.setdefault('X-Auth-User', self.auth_user)
headers.setdefault('X-User-Id', self.auth_user)
headers.setdefault('X-Auth-Project-Id', self.project_id)

response = self.request(full_uri, **kwargs)

http_status = response.status_code

+ 5
- 0
nova/tests/functional/api_sample_tests/api_sample_base.py View File

@@ -62,6 +62,11 @@ class ApiSampleTestBaseV21(testscenarios.WithScenarios,
# any additional fixtures needed for this scenario
_additional_fixtures = []
sample_dir = None
# Include the project ID in request URLs by default. This is overridden
# for certain `scenarios` and by certain subclasses.
# Note that API sample tests also use this in substitutions to validate
# that URLs in responses (e.g. location of a server just created) are
# correctly constructed.
_use_project_id = True
# Availability zones for the API samples tests. Can be overridden by
# sub-classes. If set, the AvailabilityZoneFilter is not used.

+ 1
- 0
nova/tests/functional/api_sample_tests/test_simple_tenant_usage.py View File

@@ -74,6 +74,7 @@ class SimpleTenantUsageV240Test(test_servers.ServersSampleBase):
sample_dir = 'os-simple-tenant-usage'
microversion = '2.40'
scenarios = [('v2_40', {'api_major_version': 'v2.1'})]
_use_project_id = False

def setUp(self):
super(SimpleTenantUsageV240Test, self).setUp()

+ 1
- 0
nova/tests/functional/api_sample_tests/test_versions.py View File

@@ -19,6 +19,7 @@ from nova.tests.functional.api_sample_tests import api_sample_base

class VersionsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
sample_dir = 'versions'
_use_project_id = False
# NOTE(gmann): Setting empty scenario for 'version' API testing
# as those does not send request on particular endpoint and running
# its tests alone is enough.

+ 7
- 1
nova/tests/functional/integrated_helpers.py View File

@@ -80,6 +80,9 @@ class _IntegratedTestBase(test.TestCase):
# New tests should rely on Neutron and old ones migrated to use this since
# nova-network is deprecated.
USE_NEUTRON = True
# This indicates whether to include the project ID in the URL for API
# requests through OSAPIFixture. Overridden by subclasses.
_use_project_id = False

def setUp(self):
super(_IntegratedTestBase, self).setUp()
@@ -125,8 +128,11 @@ class _IntegratedTestBase(test.TestCase):
self.scheduler = self._setup_scheduler_service()

self.compute = self._setup_compute_service()

self.api_fixture = self.useFixture(
nova_fixtures.OSAPIFixture(self.api_major_version))
nova_fixtures.OSAPIFixture(
api_version=self.api_major_version,
use_project_id_in_urls=self._use_project_id))

# if the class needs to run as admin, make the api endpoint
# the admin, otherwise it's safer to run as non admin user.

+ 6
- 2
nova/tests/functional/test_middleware.py View File

@@ -41,6 +41,10 @@ class TestCORSMiddleware(api_sample_base.ApiSampleTestBaseV21):
self._original_call_method = cfg.ConfigOpts.GroupAttr.__getattr__
cfg.ConfigOpts.GroupAttr.__getattr__ = _mock_getattr

# With the project_id in the URL, we get the 300 'multiple choices'
# response from nova.api.openstack.compute.versions.Versions.
self.exp_version_status = 300 if self._use_project_id else 200

# Initialize the application after all the config overrides are in
# place.
super(TestCORSMiddleware, self).setUp()
@@ -103,7 +107,7 @@ class TestCORSMiddleware(api_sample_base.ApiSampleTestBaseV21):
'Access-Control-Request-Method': 'GET'
})

self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, self.exp_version_status)
self.assertIn('Access-Control-Allow-Origin', response.headers)
self.assertEqual('http://valid.example.com',
response.headers['Access-Control-Allow-Origin'])
@@ -116,5 +120,5 @@ class TestCORSMiddleware(api_sample_base.ApiSampleTestBaseV21):
'Access-Control-Request-Method': 'GET'
})

self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, self.exp_version_status)
self.assertNotIn('Access-Control-Allow-Origin', response.headers)

+ 2
- 5
nova/tests/unit/api/openstack/test_requestlog.py View File

@@ -63,18 +63,15 @@ class TestRequestLogMiddleware(testtools.TestCase):
api = self.useFixture(fixtures.OSAPIFixture()).api

resp = api.api_request('/', strip_version=True)
log1 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
'"GET /v2" status: 204 len: 0 microversion: - time:')
self.assertIn(log1, self.stdlog.logger.output)

# the content length might vary, but the important part is
# what we log is what we return to the user (which turns out
# to excitingly not be the case with eventlet!)
content_length = resp.headers['content-length']

log2 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
log1 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
'"GET /" status: 200 len: %s' % content_length)
self.assertIn(log2, self.stdlog.logger.output)
self.assertIn(log1, self.stdlog.logger.output)

@mock.patch('nova.api.openstack.requestlog.RequestLog._should_emit')
def test_logs_mv(self, emit):

+ 0
- 3
nova/tests/unit/conf_fixture.py View File

@@ -45,9 +45,6 @@ class ConfFixture(config_fixture.Config):
self.conf.set_default('use_ipv6', True)
self.conf.set_default('vlan_interface', 'eth0')

# api group
self.conf.set_default('auth_strategy', 'noauth2', group='api')

# api_database group
self.conf.set_default('connection', "sqlite://", group='api_database')
self.conf.set_default('sqlite_synchronous', False,

Loading…
Cancel
Save