Add ruff
Change-Id: I0a1bfae9996c1d866a200507b59f5c76753a1aca Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
@@ -12,6 +12,12 @@ repos:
|
||||
- id: debug-statements
|
||||
- id: check-yaml
|
||||
files: .*\.(yaml|yml)$
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.13.0
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args: ['--fix', '--unsafe-fixes']
|
||||
- id: ruff-format
|
||||
- repo: https://opendev.org/openstack/hacking
|
||||
rev: 7.0.0
|
||||
hooks:
|
||||
|
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2020 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
@@ -33,7 +32,7 @@
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'openstackdocstheme'
|
||||
'openstackdocstheme',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
@@ -50,7 +49,7 @@ master_doc = 'index'
|
||||
# General information about the project.
|
||||
project = 'microversion-parse'
|
||||
copyright = '2016, OpenStack'
|
||||
author = u'OpenStack'
|
||||
author = 'OpenStack'
|
||||
|
||||
# openstackdocstheme options
|
||||
repository_name = 'openstack/microversion-parse'
|
||||
@@ -92,7 +91,7 @@ latex_documents = [
|
||||
'microversion-parse.tex',
|
||||
'microversion-parse Documentation',
|
||||
'OpenStack',
|
||||
'manual'
|
||||
'manual',
|
||||
),
|
||||
]
|
||||
|
||||
@@ -104,9 +103,9 @@ man_pages = [
|
||||
(
|
||||
master_doc,
|
||||
'microversion-parse',
|
||||
u'microversion-parse Documentation',
|
||||
'microversion-parse Documentation',
|
||||
[author],
|
||||
1
|
||||
1,
|
||||
)
|
||||
]
|
||||
|
||||
@@ -120,11 +119,11 @@ texinfo_documents = [
|
||||
(
|
||||
master_doc,
|
||||
'microversion-parse',
|
||||
u'microversion-parse Documentation',
|
||||
'microversion-parse Documentation',
|
||||
author,
|
||||
'microversion-parse',
|
||||
'One line description of project.',
|
||||
'Miscellaneous'
|
||||
'Miscellaneous',
|
||||
),
|
||||
]
|
||||
|
||||
|
@@ -26,17 +26,16 @@ class Version(collections.namedtuple('Version', 'major minor')):
|
||||
|
||||
def __new__(cls, major, minor):
|
||||
"""Add min and max version attributes to the tuple."""
|
||||
self = super(Version, cls).__new__(cls, major, minor)
|
||||
self = super().__new__(cls, major, minor)
|
||||
self.max_version = (-1, 0)
|
||||
self.min_version = (-1, 0)
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
return '%s.%s' % (self.major, self.minor)
|
||||
return f'{self.major}.{self.minor}'
|
||||
|
||||
def matches(self, min_version=None, max_version=None):
|
||||
"""Is this version within min_version and max_version.
|
||||
"""
|
||||
"""Is this version within min_version and max_version."""
|
||||
# NOTE(cdent): min_version and max_version are expected
|
||||
# to be set by the code that is creating the Version, if
|
||||
# they are known.
|
||||
@@ -155,7 +154,8 @@ def _extract_header_value(headers, header_name):
|
||||
value = headers[header_name]
|
||||
except KeyError:
|
||||
wsgi_header_name = ENVIRON_HTTP_HEADER_FMT.format(
|
||||
header_name.replace('-', '_'))
|
||||
header_name.replace('-', '_')
|
||||
)
|
||||
value = headers[wsgi_header_name]
|
||||
return value
|
||||
|
||||
@@ -173,11 +173,9 @@ def parse_version_string(version_string):
|
||||
# ValueError, TypeError or AttributeError when the incoming
|
||||
# data is poorly formed but will, however, naturally adapt to
|
||||
# extraneous whitespace.
|
||||
return Version(*(int(value) for value
|
||||
in version_string.split('.', 1)))
|
||||
return Version(*(int(value) for value in version_string.split('.', 1)))
|
||||
except (ValueError, TypeError, AttributeError) as exc:
|
||||
raise TypeError('invalid version string: %s; %s' % (
|
||||
version_string, exc))
|
||||
raise TypeError(f'invalid version string: {version_string}; {exc}')
|
||||
|
||||
|
||||
def extract_version(headers, service_type, versions_list):
|
||||
@@ -213,4 +211,4 @@ def extract_version(headers, service_type, versions_list):
|
||||
# to administratively disable a version if we really need to.
|
||||
if str(request_version) in versions_list:
|
||||
return request_version
|
||||
raise ValueError('Unacceptable version header: %s' % version_string)
|
||||
raise ValueError(f'Unacceptable version header: {version_string}')
|
||||
|
@@ -18,7 +18,7 @@ import webob.dec
|
||||
import microversion_parse
|
||||
|
||||
|
||||
class MicroversionMiddleware(object):
|
||||
class MicroversionMiddleware:
|
||||
"""WSGI middleware for getting microversion info.
|
||||
|
||||
The application will get a WSGI environ with a
|
||||
@@ -37,8 +37,9 @@ class MicroversionMiddleware(object):
|
||||
Otherwise the application is called.
|
||||
"""
|
||||
|
||||
def __init__(self, application, service_type, versions,
|
||||
json_error_formatter=None):
|
||||
def __init__(
|
||||
self, application, service_type, versions, json_error_formatter=None
|
||||
):
|
||||
"""Create the WSGI middleware.
|
||||
|
||||
:param application: The application hosting the service.
|
||||
@@ -51,7 +52,7 @@ class MicroversionMiddleware(object):
|
||||
"""
|
||||
self.application = application
|
||||
self.service_type = service_type
|
||||
self.microversion_environ = '%s.microversion' % service_type
|
||||
self.microversion_environ = f'{service_type}.microversion'
|
||||
self.versions = versions
|
||||
self.json_error_formatter = json_error_formatter
|
||||
|
||||
@@ -59,21 +60,24 @@ class MicroversionMiddleware(object):
|
||||
def __call__(self, req):
|
||||
try:
|
||||
microversion = microversion_parse.extract_version(
|
||||
req.headers, self.service_type, self.versions)
|
||||
req.headers, self.service_type, self.versions
|
||||
)
|
||||
# TODO(cdent): These error response are not formatted according to
|
||||
# api-sig guidelines, unless a json_error_formatter is provided
|
||||
# that can do it. For an example, see the placement service.
|
||||
except ValueError as exc:
|
||||
raise webob.exc.HTTPNotAcceptable(
|
||||
('Invalid microversion: %(error)s') % {'error': exc},
|
||||
json_formatter=self.json_error_formatter)
|
||||
(f'Invalid microversion: {exc}'),
|
||||
json_formatter=self.json_error_formatter,
|
||||
)
|
||||
except TypeError as exc:
|
||||
raise webob.exc.HTTPBadRequest(
|
||||
('Invalid microversion: %(error)s') % {'error': exc},
|
||||
json_formatter=self.json_error_formatter)
|
||||
(f'Invalid microversion: {exc}'),
|
||||
json_formatter=self.json_error_formatter,
|
||||
)
|
||||
|
||||
req.environ[self.microversion_environ] = microversion
|
||||
microversion_header = '%s %s' % (self.service_type, microversion)
|
||||
microversion_header = f'{self.service_type} {microversion}'
|
||||
standard_header = microversion_parse.STANDARD_HEADER
|
||||
|
||||
try:
|
||||
|
@@ -18,9 +18,8 @@ import microversion_parse
|
||||
|
||||
|
||||
class TestVersion(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestVersion, self).setUp()
|
||||
super().setUp()
|
||||
self.version = microversion_parse.Version(1, 5)
|
||||
|
||||
def test_version_is_tuple(self):
|
||||
@@ -69,7 +68,6 @@ class TestVersion(testtools.TestCase):
|
||||
|
||||
|
||||
class TestParseVersionString(testtools.TestCase):
|
||||
|
||||
def test_good_version(self):
|
||||
version = microversion_parse.parse_version_string('1.1')
|
||||
self.assertEqual((1, 1), version)
|
||||
@@ -81,57 +79,68 @@ class TestParseVersionString(testtools.TestCase):
|
||||
self.assertEqual(microversion_parse.Version(1, 1), version)
|
||||
|
||||
def test_non_numeric(self):
|
||||
self.assertRaises(TypeError,
|
||||
microversion_parse.parse_version_string,
|
||||
'hello')
|
||||
self.assertRaises(
|
||||
TypeError, microversion_parse.parse_version_string, 'hello'
|
||||
)
|
||||
|
||||
def test_mixed_alphanumeric(self):
|
||||
self.assertRaises(TypeError,
|
||||
microversion_parse.parse_version_string,
|
||||
'1.a')
|
||||
self.assertRaises(
|
||||
TypeError, microversion_parse.parse_version_string, '1.a'
|
||||
)
|
||||
|
||||
def test_too_many_numeric(self):
|
||||
self.assertRaises(TypeError,
|
||||
microversion_parse.parse_version_string,
|
||||
'1.1.1')
|
||||
self.assertRaises(
|
||||
TypeError, microversion_parse.parse_version_string, '1.1.1'
|
||||
)
|
||||
|
||||
def test_not_string(self):
|
||||
self.assertRaises(TypeError,
|
||||
microversion_parse.parse_version_string,
|
||||
1.1)
|
||||
self.assertRaises(
|
||||
TypeError, microversion_parse.parse_version_string, 1.1
|
||||
)
|
||||
|
||||
|
||||
class TestExtractVersion(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestExtractVersion, self).setUp()
|
||||
super().setUp()
|
||||
self.headers = [
|
||||
('OpenStack-API-Version', 'service1 1.2'),
|
||||
('OpenStack-API-Version', 'service2 1.5'),
|
||||
('OpenStack-API-Version', 'service3 latest'),
|
||||
('OpenStack-API-Version', 'service4 2.5'),
|
||||
]
|
||||
self.version_list = ['1.1', '1.2', '1.3', '1.4',
|
||||
'2.1', '2.2', '2.3', '2.4']
|
||||
self.version_list = [
|
||||
'1.1',
|
||||
'1.2',
|
||||
'1.3',
|
||||
'1.4',
|
||||
'2.1',
|
||||
'2.2',
|
||||
'2.3',
|
||||
'2.4',
|
||||
]
|
||||
|
||||
def test_simple_extract(self):
|
||||
version = microversion_parse.extract_version(
|
||||
self.headers, 'service1', self.version_list)
|
||||
self.headers, 'service1', self.version_list
|
||||
)
|
||||
self.assertEqual((1, 2), version)
|
||||
|
||||
def test_default_min(self):
|
||||
version = microversion_parse.extract_version(
|
||||
self.headers, 'notlisted', self.version_list)
|
||||
self.headers, 'notlisted', self.version_list
|
||||
)
|
||||
self.assertEqual((1, 1), version)
|
||||
|
||||
def test_latest(self):
|
||||
version = microversion_parse.extract_version(
|
||||
self.headers, 'service3', self.version_list)
|
||||
self.headers, 'service3', self.version_list
|
||||
)
|
||||
self.assertEqual((2, 4), version)
|
||||
|
||||
def test_min_max_extract(self):
|
||||
version = microversion_parse.extract_version(
|
||||
self.headers, 'service1', self.version_list)
|
||||
self.headers, 'service1', self.version_list
|
||||
)
|
||||
|
||||
# below min
|
||||
self.assertFalse(version.matches((1, 3)))
|
||||
@@ -144,13 +153,24 @@ class TestExtractVersion(testtools.TestCase):
|
||||
# explicit min
|
||||
self.assertFalse(version.matches(min_version=(2, 3)))
|
||||
# explicit both
|
||||
self.assertTrue(version.matches(min_version=(0, 3),
|
||||
max_version=(1, 5)))
|
||||
self.assertTrue(
|
||||
version.matches(min_version=(0, 3), max_version=(1, 5))
|
||||
)
|
||||
|
||||
def test_version_disabled(self):
|
||||
self.assertRaises(ValueError, microversion_parse.extract_version,
|
||||
self.headers, 'service2', self.version_list)
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
microversion_parse.extract_version,
|
||||
self.headers,
|
||||
'service2',
|
||||
self.version_list,
|
||||
)
|
||||
|
||||
def test_version_out_of_range(self):
|
||||
self.assertRaises(ValueError, microversion_parse.extract_version,
|
||||
self.headers, 'service4', self.version_list)
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
microversion_parse.extract_version,
|
||||
self.headers,
|
||||
'service4',
|
||||
self.version_list,
|
||||
)
|
||||
|
@@ -17,7 +17,6 @@ import microversion_parse
|
||||
|
||||
|
||||
class TestFoldHeaders(testtools.TestCase):
|
||||
|
||||
def test_dict_headers(self):
|
||||
headers = {
|
||||
'header-one': 'alpha',
|
||||
@@ -39,20 +38,19 @@ class TestFoldHeaders(testtools.TestCase):
|
||||
|
||||
folded_headers = microversion_parse.fold_headers(headers)
|
||||
self.assertEqual(2, len(folded_headers))
|
||||
self.assertEqual(set(['header-one', 'header-two']),
|
||||
set(folded_headers.keys()))
|
||||
self.assertEqual(
|
||||
set(['header-one', 'header-two']), set(folded_headers.keys())
|
||||
)
|
||||
self.assertEqual('alpha,gamma', folded_headers['header-one'])
|
||||
|
||||
def test_bad_headers(self):
|
||||
headers = 'wow this is not a headers'
|
||||
self.assertRaises(ValueError, microversion_parse.fold_headers,
|
||||
headers)
|
||||
self.assertRaises(ValueError, microversion_parse.fold_headers, headers)
|
||||
|
||||
# TODO(cdent): Test with request objects from frameworks.
|
||||
|
||||
|
||||
class TestStandardHeader(testtools.TestCase):
|
||||
|
||||
def test_simple_match(self):
|
||||
headers = {
|
||||
'header-one': 'alpha',
|
||||
@@ -88,8 +86,7 @@ class TestStandardHeader(testtools.TestCase):
|
||||
'openstack-api-version': 'network 5.9 ',
|
||||
'header-two': 'beta',
|
||||
}
|
||||
version = microversion_parse.check_standard_header(
|
||||
headers, 'compute')
|
||||
version = microversion_parse.check_standard_header(headers, 'compute')
|
||||
self.assertEqual(None, version)
|
||||
|
||||
def test_match_multiple_services(self):
|
||||
@@ -98,11 +95,11 @@ class TestStandardHeader(testtools.TestCase):
|
||||
'openstack-api-version': 'network 5.9 ,compute 2.1,telemetry 7.8',
|
||||
'header-two': 'beta',
|
||||
}
|
||||
version = microversion_parse.check_standard_header(
|
||||
headers, 'compute')
|
||||
version = microversion_parse.check_standard_header(headers, 'compute')
|
||||
self.assertEqual('2.1', version)
|
||||
version = microversion_parse.check_standard_header(
|
||||
headers, 'telemetry')
|
||||
headers, 'telemetry'
|
||||
)
|
||||
self.assertEqual('7.8', version)
|
||||
|
||||
def test_match_multiple_same_service(self):
|
||||
@@ -111,13 +108,11 @@ class TestStandardHeader(testtools.TestCase):
|
||||
'openstack-api-version': 'compute 5.9 ,compute 2.1,compute 7.8',
|
||||
'header-two': 'beta',
|
||||
}
|
||||
version = microversion_parse.check_standard_header(
|
||||
headers, 'compute')
|
||||
version = microversion_parse.check_standard_header(headers, 'compute')
|
||||
self.assertEqual('7.8', version)
|
||||
|
||||
|
||||
class TestLegacyHeaders(testtools.TestCase):
|
||||
|
||||
def test_legacy_headers_straight(self):
|
||||
headers = {
|
||||
'header-one': 'alpha',
|
||||
@@ -125,8 +120,10 @@ class TestLegacyHeaders(testtools.TestCase):
|
||||
'header-two': 'beta',
|
||||
}
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['openstack-CoMpUte-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=['openstack-CoMpUte-api-version'],
|
||||
)
|
||||
self.assertEqual('2.1', version)
|
||||
|
||||
def test_legacy_headers_folded(self):
|
||||
@@ -136,8 +133,10 @@ class TestLegacyHeaders(testtools.TestCase):
|
||||
'header-two': 'beta',
|
||||
}
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['openstack-compute-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=['openstack-compute-api-version'],
|
||||
)
|
||||
self.assertEqual('9.2', version)
|
||||
|
||||
def test_older_legacy_headers(self):
|
||||
@@ -147,9 +146,13 @@ class TestLegacyHeaders(testtools.TestCase):
|
||||
'header-two': 'beta',
|
||||
}
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['openstack-nova-api-version',
|
||||
'x-openstack-nova-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=[
|
||||
'openstack-nova-api-version',
|
||||
'x-openstack-nova-api-version',
|
||||
],
|
||||
)
|
||||
# We don't do x- for service types.
|
||||
self.assertEqual('9.2', version)
|
||||
|
||||
@@ -161,19 +164,26 @@ class TestLegacyHeaders(testtools.TestCase):
|
||||
'header-two': 'beta',
|
||||
}
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['openstack-compute-api-version',
|
||||
'x-openstack-nova-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=[
|
||||
'openstack-compute-api-version',
|
||||
'x-openstack-nova-api-version',
|
||||
],
|
||||
)
|
||||
self.assertEqual('3.7', version)
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['x-openstack-nova-api-version',
|
||||
'openstack-compute-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=[
|
||||
'x-openstack-nova-api-version',
|
||||
'openstack-compute-api-version',
|
||||
],
|
||||
)
|
||||
self.assertEqual('9.2', version)
|
||||
|
||||
|
||||
class TestGetHeaders(testtools.TestCase):
|
||||
|
||||
def test_preference(self):
|
||||
headers = {
|
||||
'header-one': 'alpha',
|
||||
@@ -183,15 +193,20 @@ class TestGetHeaders(testtools.TestCase):
|
||||
'header-two': 'beta',
|
||||
}
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['openstack-compute-api-version',
|
||||
'x-openstack-nova-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=[
|
||||
'openstack-compute-api-version',
|
||||
'x-openstack-nova-api-version',
|
||||
],
|
||||
)
|
||||
self.assertEqual('11.12', version)
|
||||
|
||||
def test_no_headers(self):
|
||||
headers = {}
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute')
|
||||
headers, service_type='compute'
|
||||
)
|
||||
self.assertEqual(None, version)
|
||||
|
||||
def test_unfolded_service(self):
|
||||
@@ -202,7 +217,8 @@ class TestGetHeaders(testtools.TestCase):
|
||||
('openstack-api-version', '3.0'),
|
||||
]
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute')
|
||||
headers, service_type='compute'
|
||||
)
|
||||
self.assertEqual('2.0', version)
|
||||
|
||||
def test_unfolded_in_name(self):
|
||||
@@ -213,15 +229,17 @@ class TestGetHeaders(testtools.TestCase):
|
||||
('openstack-telemetry-api-version', '3.0'),
|
||||
]
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['x-openstack-nova-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=['x-openstack-nova-api-version'],
|
||||
)
|
||||
self.assertEqual('2.0', version)
|
||||
|
||||
def test_capitalized_headers(self):
|
||||
headers = {
|
||||
'X-Openstack-Ironic-Api-Version': '123.456'
|
||||
}
|
||||
headers = {'X-Openstack-Ironic-Api-Version': '123.456'}
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='ironic',
|
||||
legacy_headers=['X-Openstack-Ironic-Api-Version'])
|
||||
headers,
|
||||
service_type='ironic',
|
||||
legacy_headers=['X-Openstack-Ironic-Api-Version'],
|
||||
)
|
||||
self.assertEqual('123.456', version)
|
||||
|
@@ -17,13 +17,12 @@ import microversion_parse
|
||||
|
||||
|
||||
class TestHeadersFromWSGIEnviron(testtools.TestCase):
|
||||
|
||||
def test_empty_environ(self):
|
||||
environ = {}
|
||||
expected = {}
|
||||
self.assertEqual(
|
||||
expected,
|
||||
microversion_parse.headers_from_wsgi_environ(environ))
|
||||
expected, microversion_parse.headers_from_wsgi_environ(environ)
|
||||
)
|
||||
|
||||
def test_non_empty_no_headers(self):
|
||||
environ = {'PATH_INFO': '/foo/bar'}
|
||||
@@ -32,30 +31,40 @@ class TestHeadersFromWSGIEnviron(testtools.TestCase):
|
||||
self.assertEqual(expected, found_headers)
|
||||
|
||||
def test_headers(self):
|
||||
environ = {'PATH_INFO': '/foo/bar',
|
||||
'HTTP_OPENSTACK_API_VERSION': 'placement 2.1',
|
||||
'HTTP_CONTENT_TYPE': 'application/json'}
|
||||
expected = {'HTTP_OPENSTACK_API_VERSION': 'placement 2.1',
|
||||
'HTTP_CONTENT_TYPE': 'application/json'}
|
||||
environ = {
|
||||
'PATH_INFO': '/foo/bar',
|
||||
'HTTP_OPENSTACK_API_VERSION': 'placement 2.1',
|
||||
'HTTP_CONTENT_TYPE': 'application/json',
|
||||
}
|
||||
expected = {
|
||||
'HTTP_OPENSTACK_API_VERSION': 'placement 2.1',
|
||||
'HTTP_CONTENT_TYPE': 'application/json',
|
||||
}
|
||||
found_headers = microversion_parse.headers_from_wsgi_environ(environ)
|
||||
self.assertEqual(expected, found_headers)
|
||||
|
||||
def test_get_version_from_environ(self):
|
||||
environ = {'PATH_INFO': '/foo/bar',
|
||||
'HTTP_OPENSTACK_API_VERSION': 'placement 2.1',
|
||||
'HTTP_CONTENT_TYPE': 'application/json'}
|
||||
environ = {
|
||||
'PATH_INFO': '/foo/bar',
|
||||
'HTTP_OPENSTACK_API_VERSION': 'placement 2.1',
|
||||
'HTTP_CONTENT_TYPE': 'application/json',
|
||||
}
|
||||
expected_version = '2.1'
|
||||
headers = microversion_parse.headers_from_wsgi_environ(environ)
|
||||
version = microversion_parse.get_version(headers, 'placement')
|
||||
self.assertEqual(expected_version, version)
|
||||
|
||||
def test_get_version_from_environ_legacy(self):
|
||||
environ = {'PATH_INFO': '/foo/bar',
|
||||
'HTTP_X_OPENSTACK_PLACEMENT_API_VERSION': '2.1',
|
||||
'HTTP_CONTENT_TYPE': 'application/json'}
|
||||
environ = {
|
||||
'PATH_INFO': '/foo/bar',
|
||||
'HTTP_X_OPENSTACK_PLACEMENT_API_VERSION': '2.1',
|
||||
'HTTP_CONTENT_TYPE': 'application/json',
|
||||
}
|
||||
expected_version = '2.1'
|
||||
headers = microversion_parse.headers_from_wsgi_environ(environ)
|
||||
version = microversion_parse.get_version(
|
||||
headers, 'placement',
|
||||
legacy_headers=['x-openstack-placement-api-version'])
|
||||
headers,
|
||||
'placement',
|
||||
legacy_headers=['x-openstack-placement-api-version'],
|
||||
)
|
||||
self.assertEqual(expected_version, version)
|
||||
|
@@ -32,7 +32,7 @@ VERSIONS = [
|
||||
]
|
||||
|
||||
|
||||
class SimpleWSGI(object):
|
||||
class SimpleWSGI:
|
||||
"""A WSGI application that can be contiained within a middlware."""
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
@@ -41,12 +41,13 @@ class SimpleWSGI(object):
|
||||
start_response('200 OK', [('content-type', 'text/plain')])
|
||||
return [b'good']
|
||||
|
||||
raise webob.exc.HTTPNotFound('%s not found' % path_info)
|
||||
raise webob.exc.HTTPNotFound(f'{path_info} not found')
|
||||
|
||||
|
||||
def app():
|
||||
app = middleware.MicroversionMiddleware(
|
||||
SimpleWSGI(), SERVICE_TYPE, VERSIONS)
|
||||
SimpleWSGI(), SERVICE_TYPE, VERSIONS
|
||||
)
|
||||
return app
|
||||
|
||||
|
||||
@@ -54,4 +55,5 @@ def load_tests(loader, tests, pattern):
|
||||
"""Provide a TestSuite to the discovery process."""
|
||||
test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR)
|
||||
return driver.build_tests(
|
||||
test_dir, loader, test_loader_name=__name__, intercept=app)
|
||||
test_dir, loader, test_loader_name=__name__, intercept=app
|
||||
)
|
||||
|
@@ -22,59 +22,74 @@ class TestWebobHeaders(testtools.TestCase):
|
||||
"""Webob uses a dict-like header which is not actually a dict."""
|
||||
|
||||
def test_simple_headers(self):
|
||||
headers = wb_headers.EnvironHeaders({
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
'HTTP_HEADER_THREE': 'gamma',
|
||||
})
|
||||
headers = wb_headers.EnvironHeaders(
|
||||
{
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
'HTTP_HEADER_THREE': 'gamma',
|
||||
}
|
||||
)
|
||||
|
||||
folded_headers = microversion_parse.fold_headers(headers)
|
||||
self.assertEqual(3, len(folded_headers))
|
||||
self.assertEqual(set(['header-one', 'header-three', 'header-two']),
|
||||
set(folded_headers.keys()))
|
||||
self.assertEqual(
|
||||
set(['header-one', 'header-three', 'header-two']),
|
||||
set(folded_headers.keys()),
|
||||
)
|
||||
self.assertEqual('gamma', folded_headers['header-three'])
|
||||
|
||||
def test_simple_match(self):
|
||||
headers = wb_headers.EnvironHeaders({
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_OPENSTACK_API_VERSION': 'compute 2.1',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
})
|
||||
headers = wb_headers.EnvironHeaders(
|
||||
{
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_OPENSTACK_API_VERSION': 'compute 2.1',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
}
|
||||
)
|
||||
version = microversion_parse.check_standard_header(headers, 'compute')
|
||||
self.assertEqual('2.1', version)
|
||||
|
||||
def test_match_multiple_services(self):
|
||||
headers = wb_headers.EnvironHeaders({
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_OPENSTACK_API_VERSION':
|
||||
'network 5.9 ,compute 2.1,telemetry 7.8',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
})
|
||||
version = microversion_parse.check_standard_header(
|
||||
headers, 'compute')
|
||||
headers = wb_headers.EnvironHeaders(
|
||||
{
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_OPENSTACK_API_VERSION': 'network 5.9 ,compute 2.1,telemetry 7.8',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
}
|
||||
)
|
||||
version = microversion_parse.check_standard_header(headers, 'compute')
|
||||
self.assertEqual('2.1', version)
|
||||
version = microversion_parse.check_standard_header(
|
||||
headers, 'telemetry')
|
||||
headers, 'telemetry'
|
||||
)
|
||||
self.assertEqual('7.8', version)
|
||||
|
||||
def test_legacy_headers_straight(self):
|
||||
headers = wb_headers.EnvironHeaders({
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_X_OPENSTACK_NOVA_API_VERSION': ' 2.1 ',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
})
|
||||
headers = wb_headers.EnvironHeaders(
|
||||
{
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_X_OPENSTACK_NOVA_API_VERSION': ' 2.1 ',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
}
|
||||
)
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['x-openstack-nova-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=['x-openstack-nova-api-version'],
|
||||
)
|
||||
self.assertEqual('2.1', version)
|
||||
|
||||
def test_legacy_headers_folded(self):
|
||||
headers = wb_headers.EnvironHeaders({
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_X_OPENSTACK_NOVA_API_VERSION': ' 2.1, 9.2 ',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
})
|
||||
headers = wb_headers.EnvironHeaders(
|
||||
{
|
||||
'HTTP_HEADER_ONE': 'alpha',
|
||||
'HTTP_X_OPENSTACK_NOVA_API_VERSION': ' 2.1, 9.2 ',
|
||||
'HTTP_HEADER_TWO': 'beta',
|
||||
}
|
||||
)
|
||||
version = microversion_parse.get_version(
|
||||
headers, service_type='compute',
|
||||
legacy_headers=['x-openstack-nova-api-version'])
|
||||
headers,
|
||||
service_type='compute',
|
||||
legacy_headers=['x-openstack-nova-api-version'],
|
||||
)
|
||||
self.assertEqual('9.2', version)
|
||||
|
@@ -33,3 +33,20 @@ Repository = "https://opendev.org/openstack/microversion-parse"
|
||||
packages = [
|
||||
"microversion_parse"
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 79
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "single"
|
||||
docstring-code-format = true
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E4", "E7", "E9", "F", "S", "U"]
|
||||
ignore = [
|
||||
# we only use asserts for type narrowing
|
||||
"S101",
|
||||
]
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"microversion_parse/tests/*" = ["S"]
|
||||
|
3
setup.py
3
setup.py
@@ -15,4 +15,5 @@ import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True)
|
||||
pbr=True,
|
||||
)
|
||||
|
Reference in New Issue
Block a user