Merge "Support for microversions in base Resource"
This commit is contained in:
commit
52cf40bbe5
@ -322,6 +322,11 @@ class Resource(object):
|
||||
#: Is this a detailed version of another Resource
|
||||
detail_for = None
|
||||
|
||||
#: Maximum microversion to use for getting/creating/updating the Resource
|
||||
_max_microversion = None
|
||||
#: API microversion (string or None) this Resource was loaded with
|
||||
microversion = None
|
||||
|
||||
def __init__(self, _synchronized=False, **attrs):
|
||||
"""The base resource
|
||||
|
||||
@ -330,6 +335,7 @@ class Resource(object):
|
||||
:meth:`~openstack.resource.Resource.existing`.
|
||||
"""
|
||||
|
||||
self.microversion = attrs.pop('microversion', None)
|
||||
# NOTE: _collect_attrs modifies **attrs in place, removing
|
||||
# items as they match up with any of the body, header,
|
||||
# or uri mappings.
|
||||
@ -388,6 +394,7 @@ class Resource(object):
|
||||
layer when updating instances that may have already
|
||||
been created.
|
||||
"""
|
||||
self.microversion = attrs.pop('microversion', None)
|
||||
body, header, uri = self._collect_attrs(attrs)
|
||||
|
||||
self._body.update(body)
|
||||
@ -729,6 +736,44 @@ class Resource(object):
|
||||
" instance of an openstack.proxy.Proxy object or at the very least"
|
||||
" a raw keystoneauth1.adapter.Adapter.")
|
||||
|
||||
@classmethod
|
||||
def _get_microversion_for_list(cls, session):
|
||||
"""Get microversion to use when listing resources.
|
||||
|
||||
The base version uses the following logic:
|
||||
1. If the session has a default microversion for the current service,
|
||||
just use it.
|
||||
2. If ``self._max_microversion`` is not ``None``, use minimum between
|
||||
it and the maximum microversion supported by the server.
|
||||
3. Otherwise use ``None``.
|
||||
|
||||
Subclasses can override this method if more complex logic is needed.
|
||||
|
||||
:param session: :class`keystoneauth1.adapter.Adapter`
|
||||
:return: microversion as string or ``None``
|
||||
"""
|
||||
if session.default_microversion:
|
||||
return session.default_microversion
|
||||
|
||||
return utils.maximum_supported_microversion(session,
|
||||
cls._max_microversion)
|
||||
|
||||
def _get_microversion_for(self, session, action):
|
||||
"""Get microversion to use for the given action.
|
||||
|
||||
The base version uses :meth:`_get_microversion_for_list`.
|
||||
Subclasses can override this method if more complex logic is needed.
|
||||
|
||||
:param session: :class`keystoneauth1.adapter.Adapter`
|
||||
:param action: One of "get", "update", "create", "delete". Unused in
|
||||
the base implementation.
|
||||
:return: microversion as string or ``None``
|
||||
"""
|
||||
if action not in ('get', 'update', 'create', 'delete'):
|
||||
raise ValueError('Invalid action: %s' % action)
|
||||
|
||||
return self._get_microversion_for_list(session)
|
||||
|
||||
def create(self, session, prepend_key=True):
|
||||
"""Create a remote resource based on this instance.
|
||||
|
||||
@ -746,20 +791,24 @@ class Resource(object):
|
||||
raise exceptions.MethodNotSupported(self, "create")
|
||||
|
||||
session = self._get_session(session)
|
||||
microversion = self._get_microversion_for(session, 'create')
|
||||
if self.create_method == 'PUT':
|
||||
request = self._prepare_request(requires_id=True,
|
||||
prepend_key=prepend_key)
|
||||
response = session.put(request.url,
|
||||
json=request.body, headers=request.headers)
|
||||
json=request.body, headers=request.headers,
|
||||
microversion=microversion)
|
||||
elif self.create_method == 'POST':
|
||||
request = self._prepare_request(requires_id=False,
|
||||
prepend_key=prepend_key)
|
||||
response = session.post(request.url,
|
||||
json=request.body, headers=request.headers)
|
||||
json=request.body, headers=request.headers,
|
||||
microversion=microversion)
|
||||
else:
|
||||
raise exceptions.ResourceFailure(
|
||||
msg="Invalid create method: %s" % self.create_method)
|
||||
|
||||
self.microversion = microversion
|
||||
self._translate_response(response)
|
||||
return self
|
||||
|
||||
@ -779,11 +828,13 @@ class Resource(object):
|
||||
|
||||
request = self._prepare_request(requires_id=requires_id)
|
||||
session = self._get_session(session)
|
||||
response = session.get(request.url)
|
||||
microversion = self._get_microversion_for(session, 'get')
|
||||
response = session.get(request.url, microversion=microversion)
|
||||
kwargs = {}
|
||||
if error_message:
|
||||
kwargs['error_message'] = error_message
|
||||
|
||||
self.microversion = microversion
|
||||
self._translate_response(response, **kwargs)
|
||||
return self
|
||||
|
||||
@ -803,9 +854,12 @@ class Resource(object):
|
||||
request = self._prepare_request()
|
||||
|
||||
session = self._get_session(session)
|
||||
microversion = self._get_microversion_for(session, 'get')
|
||||
response = session.head(request.url,
|
||||
headers={"Accept": ""})
|
||||
headers={"Accept": ""},
|
||||
microversion=microversion)
|
||||
|
||||
self.microversion = microversion
|
||||
self._translate_response(response, has_body=False)
|
||||
return self
|
||||
|
||||
@ -834,20 +888,25 @@ class Resource(object):
|
||||
|
||||
request = self._prepare_request(prepend_key=prepend_key)
|
||||
session = self._get_session(session)
|
||||
microversion = self._get_microversion_for(session, 'update')
|
||||
|
||||
if self.update_method == 'PATCH':
|
||||
response = session.patch(
|
||||
request.url, json=request.body, headers=request.headers)
|
||||
request.url, json=request.body, headers=request.headers,
|
||||
microversion=microversion)
|
||||
elif self.update_method == 'POST':
|
||||
response = session.post(
|
||||
request.url, json=request.body, headers=request.headers)
|
||||
request.url, json=request.body, headers=request.headers,
|
||||
microversion=microversion)
|
||||
elif self.update_method == 'PUT':
|
||||
response = session.put(
|
||||
request.url, json=request.body, headers=request.headers)
|
||||
request.url, json=request.body, headers=request.headers,
|
||||
microversion=microversion)
|
||||
else:
|
||||
raise exceptions.ResourceFailure(
|
||||
msg="Invalid update method: %s" % self.update_method)
|
||||
|
||||
self.microversion = microversion
|
||||
self._translate_response(response, has_body=has_body)
|
||||
return self
|
||||
|
||||
@ -866,9 +925,11 @@ class Resource(object):
|
||||
|
||||
request = self._prepare_request()
|
||||
session = self._get_session(session)
|
||||
microversion = self._get_microversion_for(session, 'delete')
|
||||
|
||||
response = session.delete(request.url,
|
||||
headers={"Accept": ""})
|
||||
headers={"Accept": ""},
|
||||
microversion=microversion)
|
||||
kwargs = {}
|
||||
if error_message:
|
||||
kwargs['error_message'] = error_message
|
||||
@ -910,6 +971,7 @@ class Resource(object):
|
||||
if not cls.allow_list:
|
||||
raise exceptions.MethodNotSupported(cls, "list")
|
||||
session = cls._get_session(session)
|
||||
microversion = cls._get_microversion_for_list(session)
|
||||
|
||||
cls._query_mapping._validate(params, base_path=cls.base_path)
|
||||
query_params = cls._query_mapping._transpose(params)
|
||||
@ -925,7 +987,8 @@ class Resource(object):
|
||||
response = session.get(
|
||||
uri,
|
||||
headers={"Accept": "application/json"},
|
||||
params=query_params.copy())
|
||||
params=query_params.copy(),
|
||||
microversion=microversion)
|
||||
exceptions.raise_from_response(response)
|
||||
data = response.json()
|
||||
|
||||
@ -950,7 +1013,7 @@ class Resource(object):
|
||||
# argument and is practically a reserved word.
|
||||
raw_resource.pop("self", None)
|
||||
|
||||
value = cls.existing(**raw_resource)
|
||||
value = cls.existing(microversion=microversion, **raw_resource)
|
||||
marker = value.id
|
||||
yield value
|
||||
total_yielded += 1
|
||||
|
@ -148,6 +148,7 @@ class TestLimits(base.TestCase):
|
||||
|
||||
def test_get(self):
|
||||
sess = mock.Mock(spec=adapter.Adapter)
|
||||
sess.default_microversion = None
|
||||
resp = mock.Mock()
|
||||
sess.get.return_value = resp
|
||||
resp.json.return_value = copy.deepcopy(LIMITS_BODY)
|
||||
|
@ -106,6 +106,7 @@ class TestImage(base.TestCase):
|
||||
self.resp.json = mock.Mock(return_value=self.resp.body)
|
||||
self.sess = mock.Mock(spec=adapter.Adapter)
|
||||
self.sess.post = mock.Mock(return_value=self.resp)
|
||||
self.sess.default_microversion = None
|
||||
|
||||
def test_basic(self):
|
||||
sot = image.Image()
|
||||
@ -266,7 +267,7 @@ class TestImage(base.TestCase):
|
||||
self.sess.get.assert_has_calls(
|
||||
[mock.call('images/IDENTIFIER/file',
|
||||
stream=False),
|
||||
mock.call('images/IDENTIFIER',)])
|
||||
mock.call('images/IDENTIFIER', microversion=None)])
|
||||
|
||||
self.assertEqual(rv, resp1.content)
|
||||
|
||||
@ -292,7 +293,7 @@ class TestImage(base.TestCase):
|
||||
self.sess.get.assert_has_calls(
|
||||
[mock.call('images/IDENTIFIER/file',
|
||||
stream=False),
|
||||
mock.call('images/IDENTIFIER',)])
|
||||
mock.call('images/IDENTIFIER', microversion=None)])
|
||||
|
||||
self.assertEqual(rv, resp1.content)
|
||||
|
||||
|
@ -76,6 +76,7 @@ class TestFloatingIP(base.TestCase):
|
||||
def test_find_available(self):
|
||||
mock_session = mock.Mock(spec=adapter.Adapter)
|
||||
mock_session.get_filter = mock.Mock(return_value={})
|
||||
mock_session.default_microversion = None
|
||||
data = {'id': 'one', 'floating_ip_address': '10.0.0.1'}
|
||||
fake_response = mock.Mock()
|
||||
body = {floating_ip.FloatingIP.resources_key: [data]}
|
||||
@ -89,10 +90,12 @@ class TestFloatingIP(base.TestCase):
|
||||
mock_session.get.assert_called_with(
|
||||
floating_ip.FloatingIP.base_path,
|
||||
headers={'Accept': 'application/json'},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
def test_find_available_nada(self):
|
||||
mock_session = mock.Mock(spec=adapter.Adapter)
|
||||
mock_session.default_microversion = None
|
||||
fake_response = mock.Mock()
|
||||
body = {floating_ip.FloatingIP.resources_key: []}
|
||||
fake_response.json = mock.Mock(return_value=body)
|
||||
|
@ -976,8 +976,14 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.post = mock.Mock(return_value=self.response)
|
||||
self.session.delete = mock.Mock(return_value=self.response)
|
||||
self.session.head = mock.Mock(return_value=self.response)
|
||||
self.session.default_microversion = None
|
||||
|
||||
def _test_create(self, cls, requires_id=False, prepend_key=False):
|
||||
self.endpoint_data = mock.Mock(max_microversion='1.99',
|
||||
min_microversion=None)
|
||||
self.session.get_endpoint_data.return_value = self.endpoint_data
|
||||
|
||||
def _test_create(self, cls, requires_id=False, prepend_key=False,
|
||||
microversion=None):
|
||||
id = "id" if requires_id else None
|
||||
sot = cls(id=id)
|
||||
sot._prepare_request = mock.Mock(return_value=self.request)
|
||||
@ -990,12 +996,15 @@ class TestResourceActions(base.TestCase):
|
||||
if requires_id:
|
||||
self.session.put.assert_called_once_with(
|
||||
self.request.url,
|
||||
json=self.request.body, headers=self.request.headers)
|
||||
json=self.request.body, headers=self.request.headers,
|
||||
microversion=microversion)
|
||||
else:
|
||||
self.session.post.assert_called_once_with(
|
||||
self.request.url,
|
||||
json=self.request.body, headers=self.request.headers)
|
||||
json=self.request.body, headers=self.request.headers,
|
||||
microversion=microversion)
|
||||
|
||||
self.assertEqual(sot.microversion, microversion)
|
||||
sot._translate_response.assert_called_once_with(self.response)
|
||||
self.assertEqual(result, sot)
|
||||
|
||||
@ -1008,6 +1017,17 @@ class TestResourceActions(base.TestCase):
|
||||
|
||||
self._test_create(Test, requires_id=True, prepend_key=True)
|
||||
|
||||
def test_put_create_with_microversion(self):
|
||||
class Test(resource.Resource):
|
||||
service = self.service_name
|
||||
base_path = self.base_path
|
||||
allow_create = True
|
||||
create_method = 'PUT'
|
||||
_max_microversion = '1.42'
|
||||
|
||||
self._test_create(Test, requires_id=True, prepend_key=True,
|
||||
microversion='1.42')
|
||||
|
||||
def test_post_create(self):
|
||||
class Test(resource.Resource):
|
||||
service = self.service_name
|
||||
@ -1022,17 +1042,39 @@ class TestResourceActions(base.TestCase):
|
||||
|
||||
self.sot._prepare_request.assert_called_once_with(requires_id=True)
|
||||
self.session.get.assert_called_once_with(
|
||||
self.request.url,)
|
||||
self.request.url, microversion=None)
|
||||
|
||||
self.assertIsNone(self.sot.microversion)
|
||||
self.sot._translate_response.assert_called_once_with(self.response)
|
||||
self.assertEqual(result, self.sot)
|
||||
|
||||
def test_get_with_microversion(self):
|
||||
class Test(resource.Resource):
|
||||
service = self.service_name
|
||||
base_path = self.base_path
|
||||
allow_get = True
|
||||
_max_microversion = '1.42'
|
||||
|
||||
sot = Test(id='id')
|
||||
sot._prepare_request = mock.Mock(return_value=self.request)
|
||||
sot._translate_response = mock.Mock()
|
||||
|
||||
result = sot.get(self.session)
|
||||
|
||||
sot._prepare_request.assert_called_once_with(requires_id=True)
|
||||
self.session.get.assert_called_once_with(
|
||||
self.request.url, microversion='1.42')
|
||||
|
||||
self.assertEqual(sot.microversion, '1.42')
|
||||
sot._translate_response.assert_called_once_with(self.response)
|
||||
self.assertEqual(result, sot)
|
||||
|
||||
def test_get_not_requires_id(self):
|
||||
result = self.sot.get(self.session, False)
|
||||
|
||||
self.sot._prepare_request.assert_called_once_with(requires_id=False)
|
||||
self.session.get.assert_called_once_with(
|
||||
self.request.url,)
|
||||
self.request.url, microversion=None)
|
||||
|
||||
self.sot._translate_response.assert_called_once_with(self.response)
|
||||
self.assertEqual(result, self.sot)
|
||||
@ -1043,14 +1085,40 @@ class TestResourceActions(base.TestCase):
|
||||
self.sot._prepare_request.assert_called_once_with()
|
||||
self.session.head.assert_called_once_with(
|
||||
self.request.url,
|
||||
headers={"Accept": ""})
|
||||
headers={"Accept": ""},
|
||||
microversion=None)
|
||||
|
||||
self.assertIsNone(self.sot.microversion)
|
||||
self.sot._translate_response.assert_called_once_with(
|
||||
self.response, has_body=False)
|
||||
self.assertEqual(result, self.sot)
|
||||
|
||||
def test_head_with_microversion(self):
|
||||
class Test(resource.Resource):
|
||||
service = self.service_name
|
||||
base_path = self.base_path
|
||||
allow_head = True
|
||||
_max_microversion = '1.42'
|
||||
|
||||
sot = Test(id='id')
|
||||
sot._prepare_request = mock.Mock(return_value=self.request)
|
||||
sot._translate_response = mock.Mock()
|
||||
|
||||
result = sot.head(self.session)
|
||||
|
||||
sot._prepare_request.assert_called_once_with()
|
||||
self.session.head.assert_called_once_with(
|
||||
self.request.url,
|
||||
headers={"Accept": ""},
|
||||
microversion='1.42')
|
||||
|
||||
self.assertEqual(sot.microversion, '1.42')
|
||||
sot._translate_response.assert_called_once_with(
|
||||
self.response, has_body=False)
|
||||
self.assertEqual(result, sot)
|
||||
|
||||
def _test_update(self, update_method='PUT', prepend_key=True,
|
||||
has_body=True):
|
||||
has_body=True, microversion=None):
|
||||
self.sot.update_method = update_method
|
||||
|
||||
# Need to make sot look dirty so we can attempt an update
|
||||
@ -1066,16 +1134,20 @@ class TestResourceActions(base.TestCase):
|
||||
if update_method == 'PATCH':
|
||||
self.session.patch.assert_called_once_with(
|
||||
self.request.url,
|
||||
json=self.request.body, headers=self.request.headers)
|
||||
json=self.request.body, headers=self.request.headers,
|
||||
microversion=microversion)
|
||||
elif update_method == 'POST':
|
||||
self.session.post.assert_called_once_with(
|
||||
self.request.url,
|
||||
json=self.request.body, headers=self.request.headers)
|
||||
json=self.request.body, headers=self.request.headers,
|
||||
microversion=microversion)
|
||||
elif update_method == 'PUT':
|
||||
self.session.put.assert_called_once_with(
|
||||
self.request.url,
|
||||
json=self.request.body, headers=self.request.headers)
|
||||
json=self.request.body, headers=self.request.headers,
|
||||
microversion=microversion)
|
||||
|
||||
self.assertEqual(self.sot.microversion, microversion)
|
||||
self.sot._translate_response.assert_called_once_with(
|
||||
self.response, has_body=has_body)
|
||||
|
||||
@ -1102,12 +1174,36 @@ class TestResourceActions(base.TestCase):
|
||||
self.sot._prepare_request.assert_called_once_with()
|
||||
self.session.delete.assert_called_once_with(
|
||||
self.request.url,
|
||||
headers={"Accept": ""})
|
||||
headers={"Accept": ""},
|
||||
microversion=None)
|
||||
|
||||
self.sot._translate_response.assert_called_once_with(
|
||||
self.response, has_body=False)
|
||||
self.assertEqual(result, self.sot)
|
||||
|
||||
def test_delete_with_microversion(self):
|
||||
class Test(resource.Resource):
|
||||
service = self.service_name
|
||||
base_path = self.base_path
|
||||
allow_delete = True
|
||||
_max_microversion = '1.42'
|
||||
|
||||
sot = Test(id='id')
|
||||
sot._prepare_request = mock.Mock(return_value=self.request)
|
||||
sot._translate_response = mock.Mock()
|
||||
|
||||
result = sot.delete(self.session)
|
||||
|
||||
sot._prepare_request.assert_called_once_with()
|
||||
self.session.delete.assert_called_once_with(
|
||||
self.request.url,
|
||||
headers={"Accept": ""},
|
||||
microversion='1.42')
|
||||
|
||||
sot._translate_response.assert_called_once_with(
|
||||
self.response, has_body=False)
|
||||
self.assertEqual(result, sot)
|
||||
|
||||
# NOTE: As list returns a generator, testing it requires consuming
|
||||
# the generator. Wrap calls to self.sot.list in a `list`
|
||||
# and then test the results as a list of responses.
|
||||
@ -1123,7 +1219,8 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_once_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
self.assertEqual([], result)
|
||||
|
||||
@ -1159,7 +1256,8 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_once_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
self.assertEqual(1, len(results))
|
||||
self.assertEqual(id_value, results[0].id)
|
||||
@ -1185,7 +1283,8 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_once_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
self.assertEqual(1, len(results))
|
||||
self.assertEqual(id_value, results[0].id)
|
||||
@ -1219,11 +1318,13 @@ class TestResourceActions(base.TestCase):
|
||||
self.assertEqual(ids[1], results[1].id)
|
||||
self.assertEqual(
|
||||
mock.call('base_path',
|
||||
headers={'Accept': 'application/json'}, params={}),
|
||||
headers={'Accept': 'application/json'}, params={},
|
||||
microversion=None),
|
||||
self.session.get.mock_calls[0])
|
||||
self.assertEqual(
|
||||
mock.call('https://example.com/next-url',
|
||||
headers={'Accept': 'application/json'}, params={}),
|
||||
headers={'Accept': 'application/json'}, params={},
|
||||
microversion=None),
|
||||
self.session.get.mock_calls[1])
|
||||
self.assertEqual(2, len(self.session.get.call_args_list))
|
||||
self.assertIsInstance(results[0], self.test_class)
|
||||
@ -1253,15 +1354,64 @@ class TestResourceActions(base.TestCase):
|
||||
self.assertEqual(ids[1], results[1].id)
|
||||
self.assertEqual(
|
||||
mock.call('base_path',
|
||||
headers={'Accept': 'application/json'}, params={}),
|
||||
headers={'Accept': 'application/json'}, params={},
|
||||
microversion=None),
|
||||
self.session.get.mock_calls[0])
|
||||
self.assertEqual(
|
||||
mock.call('https://example.com/next-url',
|
||||
headers={'Accept': 'application/json'}, params={}),
|
||||
headers={'Accept': 'application/json'}, params={},
|
||||
microversion=None),
|
||||
self.session.get.mock_calls[2])
|
||||
self.assertEqual(2, len(self.session.get.call_args_list))
|
||||
self.assertIsInstance(results[0], self.test_class)
|
||||
|
||||
def test_list_response_paginated_with_microversions(self):
|
||||
class Test(resource.Resource):
|
||||
service = self.service_name
|
||||
base_path = self.base_path
|
||||
resources_key = 'resources'
|
||||
allow_list = True
|
||||
_max_microversion = '1.42'
|
||||
|
||||
ids = [1, 2]
|
||||
mock_response = mock.Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.links = {}
|
||||
mock_response.json.return_value = {
|
||||
"resources": [{"id": ids[0]}],
|
||||
"resources_links": [{
|
||||
"href": "https://example.com/next-url",
|
||||
"rel": "next",
|
||||
}]
|
||||
}
|
||||
mock_response2 = mock.Mock()
|
||||
mock_response2.status_code = 200
|
||||
mock_response2.links = {}
|
||||
mock_response2.json.return_value = {
|
||||
"resources": [{"id": ids[1]}],
|
||||
}
|
||||
|
||||
self.session.get.side_effect = [mock_response, mock_response2]
|
||||
|
||||
results = list(Test.list(self.session, paginated=True))
|
||||
|
||||
self.assertEqual(2, len(results))
|
||||
self.assertEqual(ids[0], results[0].id)
|
||||
self.assertEqual(ids[1], results[1].id)
|
||||
self.assertEqual(
|
||||
mock.call('base_path',
|
||||
headers={'Accept': 'application/json'}, params={},
|
||||
microversion='1.42'),
|
||||
self.session.get.mock_calls[0])
|
||||
self.assertEqual(
|
||||
mock.call('https://example.com/next-url',
|
||||
headers={'Accept': 'application/json'}, params={},
|
||||
microversion='1.42'),
|
||||
self.session.get.mock_calls[1])
|
||||
self.assertEqual(2, len(self.session.get.call_args_list))
|
||||
self.assertIsInstance(results[0], Test)
|
||||
self.assertEqual('1.42', results[0].microversion)
|
||||
|
||||
def test_list_multi_page_response_not_paginated(self):
|
||||
ids = [1, 2]
|
||||
mock_response = mock.Mock()
|
||||
@ -1453,20 +1603,23 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
result1 = next(results)
|
||||
self.assertEqual(result1.id, ids[1])
|
||||
self.session.get.assert_called_with(
|
||||
'https://example.com/next-url',
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
self.assertRaises(StopIteration, next, results)
|
||||
self.session.get.assert_called_with(
|
||||
'https://example.com/next-url',
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
def test_list_multi_page_no_early_termination(self):
|
||||
# This tests verifies that multipages are not early terminated.
|
||||
@ -1508,7 +1661,8 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={"limit": 3})
|
||||
params={"limit": 3},
|
||||
microversion=None)
|
||||
|
||||
# Second page contains another two items
|
||||
result2 = next(results)
|
||||
@ -1518,7 +1672,8 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={"limit": 3, "marker": 2})
|
||||
params={"limit": 3, "marker": 2},
|
||||
microversion=None)
|
||||
|
||||
# Ensure we're done after those four items
|
||||
self.assertRaises(StopIteration, next, results)
|
||||
@ -1527,7 +1682,8 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={"limit": 3, "marker": 4})
|
||||
params={"limit": 3, "marker": 4},
|
||||
microversion=None)
|
||||
|
||||
# Ensure we made three calls to get this done
|
||||
self.assertEqual(3, len(self.session.get.call_args_list))
|
||||
@ -1564,14 +1720,16 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={"limit": 2})
|
||||
params={"limit": 2},
|
||||
microversion=None)
|
||||
|
||||
result2 = next(results)
|
||||
self.assertEqual(result2.id, ids[2])
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={'limit': 2, 'marker': 2})
|
||||
params={'limit': 2, 'marker': 2},
|
||||
microversion=None)
|
||||
|
||||
# Ensure we're done after those three items
|
||||
self.assertRaises(StopIteration, next, results)
|
||||
@ -1612,14 +1770,16 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
result2 = next(results)
|
||||
self.assertEqual(result2.id, ids[2])
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={'marker': 2})
|
||||
params={'marker': 2},
|
||||
microversion=None)
|
||||
|
||||
# Ensure we're done after those three items
|
||||
self.assertRaises(StopIteration, next, results)
|
||||
@ -1658,14 +1818,16 @@ class TestResourceActions(base.TestCase):
|
||||
self.session.get.assert_called_with(
|
||||
self.base_path,
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
result2 = next(results)
|
||||
self.assertEqual(result2.id, ids[2])
|
||||
self.session.get.assert_called_with(
|
||||
'https://example.com/next-url',
|
||||
headers={"Accept": "application/json"},
|
||||
params={})
|
||||
params={},
|
||||
microversion=None)
|
||||
|
||||
# Ensure we're done after those three items
|
||||
self.assertRaises(StopIteration, next, results)
|
||||
|
@ -104,3 +104,33 @@ class Test_urljoin(base.TestCase):
|
||||
|
||||
result = utils.urljoin(root, *leaves)
|
||||
self.assertEqual(result, "http://www.example.com/foo/")
|
||||
|
||||
|
||||
class TestMaximumSupportedMicroversion(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestMaximumSupportedMicroversion, self).setUp()
|
||||
self.adapter = mock.Mock(spec=['get_endpoint_data'])
|
||||
self.endpoint_data = mock.Mock(spec=['min_microversion',
|
||||
'max_microversion'],
|
||||
min_microversion=None,
|
||||
max_microversion='1.99')
|
||||
self.adapter.get_endpoint_data.return_value = self.endpoint_data
|
||||
|
||||
def test_with_none(self):
|
||||
self.assertIsNone(utils.maximum_supported_microversion(self.adapter,
|
||||
None))
|
||||
|
||||
def test_with_value(self):
|
||||
self.assertEqual('1.42',
|
||||
utils.maximum_supported_microversion(self.adapter,
|
||||
'1.42'))
|
||||
|
||||
def test_value_more_than_max(self):
|
||||
self.assertEqual('1.99',
|
||||
utils.maximum_supported_microversion(self.adapter,
|
||||
'1.100'))
|
||||
|
||||
def test_value_less_than_min(self):
|
||||
self.endpoint_data.min_microversion = '1.42'
|
||||
self.assertIsNone(utils.maximum_supported_microversion(self.adapter,
|
||||
'1.2'))
|
||||
|
@ -183,3 +183,35 @@ def pick_microversion(session, required):
|
||||
|
||||
if required is not None:
|
||||
return discover.version_to_string(required)
|
||||
|
||||
|
||||
def maximum_supported_microversion(adapter, client_maximum):
|
||||
"""Determinte the maximum microversion supported by both client and server.
|
||||
|
||||
:param adapter: :class:`~keystoneauth1.adapter.Adapter` instance.
|
||||
:param client_maximum: Maximum microversion supported by the client.
|
||||
If ``None``, ``None`` is returned.
|
||||
|
||||
:returns: the maximum supported microversion as string or ``None``.
|
||||
"""
|
||||
if client_maximum is None:
|
||||
return None
|
||||
|
||||
endpoint_data = adapter.get_endpoint_data()
|
||||
if not endpoint_data.max_microversion:
|
||||
return None
|
||||
|
||||
client_max = discover.normalize_version_number(client_maximum)
|
||||
server_max = discover.normalize_version_number(
|
||||
endpoint_data.max_microversion)
|
||||
|
||||
if endpoint_data.min_microversion:
|
||||
server_min = discover.normalize_version_number(
|
||||
endpoint_data.min_microversion)
|
||||
if client_max < server_min:
|
||||
# NOTE(dtantsur): we may want to raise in this case, but this keeps
|
||||
# the current behavior intact.
|
||||
return None
|
||||
|
||||
result = min(client_max, server_max)
|
||||
return discover.version_to_string(result)
|
||||
|
Loading…
Reference in New Issue
Block a user