Remove resource and proxy
Step one in the final removal of resource/proxy v1. Doing it as a two commit chain just as a sanity check. All of the services have been migrated to Resource2/Proxy2. Before we rename those back to Resource/Proxy, delete the v1 versions and make sure everything is still happy. The next patch will do the renames. Change-Id: I254a7474236ea4959db1bd00b397320b0ca27387
This commit is contained in:
parent
3326bb01aa
commit
aebf019660
@ -1,7 +1,7 @@
|
||||
# Apache 2 header omitted for brevity
|
||||
|
||||
from openstack.fake import fake_service
|
||||
from openstack import resource
|
||||
from openstack import resource2 as resource
|
||||
|
||||
|
||||
class Fake(resource.Resource):
|
||||
@ -9,21 +9,20 @@ class Fake(resource.Resource):
|
||||
resources_key = "resources"
|
||||
base_path = "/fake"
|
||||
service = fake_service.FakeService()
|
||||
id_attribute = "name"
|
||||
|
||||
allow_create = True
|
||||
allow_retrieve = True
|
||||
allow_get = True
|
||||
allow_update = True
|
||||
allow_delete = True
|
||||
allow_list = True
|
||||
allow_head = True
|
||||
|
||||
#: The transaction date and time.
|
||||
timestamp = resource.prop("x-timestamp")
|
||||
timestamp = resource.Header("x-timestamp")
|
||||
#: The name of this resource.
|
||||
name = resource.prop("name")
|
||||
name = resource.Body("name", alternate_id=True)
|
||||
#: The value of the resource. Also available in headers.
|
||||
value = resource.prop("value", alias="x-resource-value")
|
||||
value = resource.Body("value", alias="x-resource-value")
|
||||
#: Is this resource cool? If so, set it to True.
|
||||
#: This is a multi-line comment about cool stuff.
|
||||
cool = resource.prop("cool", type=bool)
|
||||
cool = resource.Body("cool", type=bool)
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. TODO(shade) Update this guide.
|
||||
|
||||
Creating a New Resource
|
||||
=======================
|
||||
|
||||
@ -108,14 +110,6 @@ service is called in the service catalog. When a request is made for this
|
||||
resource, the Session now knows how to construct the appropriate URL using
|
||||
this ``FakeService`` instance.
|
||||
|
||||
``id_attribute``
|
||||
****************
|
||||
|
||||
*Line 12* specifies that this resource uses a different identifier than
|
||||
the default of ``id``. While IDs are used internally, such as for creating
|
||||
request URLs to interact with an individual resource, they are exposed for
|
||||
consistency so users always have one place to find the resource's identity.
|
||||
|
||||
Supported Operations
|
||||
--------------------
|
||||
|
||||
@ -136,7 +130,7 @@ value by setting it to ``True``:
|
||||
+----------------------------------------------+----------------+
|
||||
| :class:`~openstack.resource.Resource.list` | allow_list |
|
||||
+----------------------------------------------+----------------+
|
||||
| :class:`~openstack.resource.Resource.get` | allow_retrieve |
|
||||
| :class:`~openstack.resource.Resource.get` | allow_get |
|
||||
+----------------------------------------------+----------------+
|
||||
| :class:`~openstack.resource.Resource.update` | allow_update |
|
||||
+----------------------------------------------+----------------+
|
||||
@ -148,6 +142,8 @@ used for ``Resource.update``.
|
||||
Properties
|
||||
----------
|
||||
|
||||
.. TODO(shade) Especially this section
|
||||
|
||||
The way resource classes communicate values between the user and the server
|
||||
are :class:`~openstack.resource.prop` objects. These act similarly to Python's
|
||||
built-in property objects, but they share only the name - they're not the same.
|
||||
|
@ -137,7 +137,6 @@ can be customized.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
resource
|
||||
resource2
|
||||
service_filter
|
||||
utils
|
||||
|
@ -1,39 +0,0 @@
|
||||
**NOTE: This module is being phased out in favor of**
|
||||
:mod:`openstack.resource2`. **Once all services have been moved over to use
|
||||
resource2, that module will take this `resource` name.**
|
||||
|
||||
Resource
|
||||
========
|
||||
.. automodule:: openstack.resource
|
||||
|
||||
The prop class
|
||||
--------------
|
||||
|
||||
.. autoclass:: openstack.resource.prop
|
||||
:members:
|
||||
|
||||
The Resource class
|
||||
------------------
|
||||
|
||||
.. autoclass:: openstack.resource.Resource
|
||||
:members:
|
||||
:member-order: bysource
|
||||
|
||||
How path_args are used
|
||||
**********************
|
||||
|
||||
As :class:`Resource`\s often contain compound :data:`Resource.base_path`\s,
|
||||
meaning the path is constructed from more than just that string, the
|
||||
various request methods need a way to fill in the missing parts.
|
||||
That's where ``path_args`` come in.
|
||||
|
||||
For example::
|
||||
|
||||
class ServerIP(resource.Resource):
|
||||
base_path = "/servers/%(server_id)s/ips"
|
||||
|
||||
Making a GET request to obtain server IPs requires the ID of the server
|
||||
to check. This is handled by passing ``{"server_id": "12345"}`` as the
|
||||
``path_args`` argument when calling :meth:`Resource.get_by_id`. From there,
|
||||
the method uses Python's string interpolation to fill in the ``server_id``
|
||||
piece of the URL, and then makes the request.
|
@ -1,286 +0,0 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from openstack import _adapter
|
||||
from openstack import exceptions
|
||||
from openstack import resource
|
||||
|
||||
|
||||
# The _check_resource decorator is used on BaseProxy methods to ensure that
|
||||
# the `actual` argument is in fact the type of the `expected` argument.
|
||||
# It does so under two cases:
|
||||
# 1. When strict=False, if and only if `actual` is a Resource instance,
|
||||
# it is checked to see that it's an instance of the `expected` class.
|
||||
# This allows `actual` to be other types, such as strings, when it makes
|
||||
# sense to accept a raw id value.
|
||||
# 2. When strict=True, `actual` must be an instance of the `expected` class.
|
||||
def _check_resource(strict=False):
|
||||
def wrap(method):
|
||||
def check(self, expected, actual=None, *args, **kwargs):
|
||||
if (strict and actual is not None and not
|
||||
isinstance(actual, resource.Resource)):
|
||||
raise ValueError("A %s must be passed" % expected.__name__)
|
||||
elif (isinstance(actual, resource.Resource) and not
|
||||
isinstance(actual, expected)):
|
||||
raise ValueError("Expected %s but received %s" % (
|
||||
expected.__name__, actual.__class__.__name__))
|
||||
|
||||
return method(self, expected, actual, *args, **kwargs)
|
||||
return check
|
||||
return wrap
|
||||
|
||||
|
||||
class BaseProxy(_adapter.OpenStackSDKAdapter):
|
||||
|
||||
def _get_resource(self, resource_type, value, path_args=None):
|
||||
"""Get a resource object to work on
|
||||
|
||||
:param resource_type: The type of resource to operate on. This should
|
||||
be a subclass of
|
||||
:class:`~openstack.resource.Resource` with a
|
||||
``from_id`` method.
|
||||
:param value: The ID of a resource or an object of ``resource_type``
|
||||
class if using an existing instance, or None to create a
|
||||
new instance.
|
||||
:param path_args: A dict containing arguments for forming the request
|
||||
URL, if needed.
|
||||
"""
|
||||
if value is None:
|
||||
# Create a bare resource
|
||||
res = resource_type()
|
||||
elif not isinstance(value, resource_type):
|
||||
# Create from an ID
|
||||
args = {resource_type.id_attribute:
|
||||
resource.Resource.get_id(value)}
|
||||
res = resource_type.existing(**args)
|
||||
else:
|
||||
# An existing resource instance
|
||||
res = value
|
||||
|
||||
# Set any intermediate path arguments, but don't overwrite Nones.
|
||||
if path_args is not None:
|
||||
res.update_attrs(ignore_none=True, **path_args)
|
||||
|
||||
return res
|
||||
|
||||
def _find(self, resource_type, name_or_id, path_args=None,
|
||||
ignore_missing=True):
|
||||
"""Find a resource
|
||||
|
||||
:param name_or_id: The name or ID of a resource to find.
|
||||
:param bool ignore_missing: When set to ``False``
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be
|
||||
raised when the resource does not exist.
|
||||
When set to ``True``, None will be returned when
|
||||
attempting to find a nonexistent resource.
|
||||
|
||||
:returns: An instance of ``resource_type`` or None
|
||||
"""
|
||||
return resource_type.find(self, name_or_id,
|
||||
path_args=path_args,
|
||||
ignore_missing=ignore_missing)
|
||||
|
||||
@_check_resource(strict=False)
|
||||
def _delete(self, resource_type, value, path_args=None,
|
||||
ignore_missing=True):
|
||||
"""Delete a resource
|
||||
|
||||
:param resource_type: The type of resource to delete. This should
|
||||
be a :class:`~openstack.resource.Resource`
|
||||
subclass with a ``from_id`` method.
|
||||
:param value: The value to delete. Can be either the ID of a
|
||||
resource or a :class:`~openstack.resource.Resource`
|
||||
subclass.
|
||||
:param path_args: A dict containing arguments for forming the request
|
||||
URL, if needed.
|
||||
:param bool ignore_missing: When set to ``False``
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be
|
||||
raised when the resource does not exist.
|
||||
When set to ``True``, no exception will be set when
|
||||
attempting to delete a nonexistent resource.
|
||||
|
||||
:returns: The result of the ``delete``
|
||||
:raises: ``ValueError`` if ``value`` is a
|
||||
:class:`~openstack.resource.Resource` that doesn't match
|
||||
the ``resource_type``.
|
||||
:class:`~openstack.exceptions.ResourceNotFound` when
|
||||
ignore_missing if ``False`` and a nonexistent resource
|
||||
is attempted to be deleted.
|
||||
|
||||
"""
|
||||
res = self._get_resource(resource_type, value, path_args)
|
||||
|
||||
try:
|
||||
rv = res.delete(
|
||||
self,
|
||||
error_message="No {resource_type} found for {value}".format(
|
||||
resource_type=resource_type.__name__, value=value))
|
||||
except exceptions.NotFoundException:
|
||||
if ignore_missing:
|
||||
return None
|
||||
else:
|
||||
raise
|
||||
|
||||
return rv
|
||||
|
||||
@_check_resource(strict=False)
|
||||
def _update(self, resource_type, value, path_args=None, **attrs):
|
||||
"""Update a resource
|
||||
|
||||
:param resource_type: The type of resource to update.
|
||||
:type resource_type: :class:`~openstack.resource.Resource`
|
||||
:param value: The resource to update. This must either be a
|
||||
:class:`~openstack.resource.Resource` or an id
|
||||
that corresponds to a resource.
|
||||
:param path_args: A dict containing arguments for forming the request
|
||||
URL, if needed.
|
||||
:param **attrs: Attributes to update on a Resource object.
|
||||
These attributes will be used in conjunction with
|
||||
``resource_type``.
|
||||
|
||||
:returns: The result of the ``update``
|
||||
:rtype: :class:`~openstack.resource.Resource`
|
||||
"""
|
||||
res = self._get_resource(resource_type, value, path_args)
|
||||
res.update_attrs(attrs)
|
||||
return res.update(self)
|
||||
|
||||
def _create(self, resource_type, path_args=None, **attrs):
|
||||
"""Create a resource from attributes
|
||||
|
||||
:param resource_type: The type of resource to create.
|
||||
:type resource_type: :class:`~openstack.resource.Resource`
|
||||
:param path_args: A dict containing arguments for forming the request
|
||||
URL, if needed.
|
||||
:param **attrs: Attributes from which to create a Resource object.
|
||||
These attributes will be used in conjunction with
|
||||
``resource_type``.
|
||||
|
||||
:returns: The result of the ``create``
|
||||
:rtype: :class:`~openstack.resource.Resource`
|
||||
"""
|
||||
res = resource_type.new(**attrs)
|
||||
if path_args is not None:
|
||||
res.update_attrs(path_args)
|
||||
return res.create(self)
|
||||
|
||||
@_check_resource(strict=False)
|
||||
def _get(self, resource_type, value=None, path_args=None, args=None):
|
||||
"""Get a resource
|
||||
|
||||
:param resource_type: The type of resource to get.
|
||||
:type resource_type: :class:`~openstack.resource.Resource`
|
||||
:param value: The value to get. Can be either the ID of a
|
||||
resource or a :class:`~openstack.resource.Resource`
|
||||
subclass.
|
||||
:param path_args: A dict containing arguments for forming the request
|
||||
URL, if needed.
|
||||
:param args: A optional dict containing arguments that will be
|
||||
translated into query strings when forming the request URL.
|
||||
|
||||
:returns: The result of the ``get``
|
||||
:rtype: :class:`~openstack.resource.Resource`
|
||||
"""
|
||||
res = self._get_resource(resource_type, value, path_args)
|
||||
|
||||
return res.get(
|
||||
self, args=args,
|
||||
error_message='No {resource} found for {value}'.format(
|
||||
resource=resource_type.__name__, value=value))
|
||||
|
||||
def _list(self, resource_type, value=None, paginated=False,
|
||||
path_args=None, **query):
|
||||
"""List a resource
|
||||
|
||||
:param resource_type: The type of resource to delete. This should
|
||||
be a :class:`~openstack.resource.Resource`
|
||||
subclass with a ``from_id`` method.
|
||||
:param value: The resource to list. It can be the ID of a resource, or
|
||||
a :class:`~openstack.resource.Resource` object. When set
|
||||
to None, a new bare resource is created.
|
||||
:param bool paginated: When set to ``False``, expect all of the data
|
||||
to be returned in one response. When set to
|
||||
``True``, the resource supports data being
|
||||
returned across multiple pages.
|
||||
:param path_args: A dictionary containing arguments for use when
|
||||
forming the request URL for resource retrieval.
|
||||
:param kwargs **query: Keyword arguments that are sent to the list
|
||||
method, which are then attached as query
|
||||
parameters on the request URL.
|
||||
|
||||
:returns: A generator of Resource objects.
|
||||
:raises: ``ValueError`` if ``value`` is a
|
||||
:class:`~openstack.resource.Resource` that doesn't match
|
||||
the ``resource_type``.
|
||||
"""
|
||||
res = self._get_resource(resource_type, value, path_args)
|
||||
|
||||
query = res.convert_ids(query)
|
||||
return res.list(self, path_args=path_args,
|
||||
paginated=paginated, params=query)
|
||||
|
||||
def _head(self, resource_type, value=None, path_args=None):
|
||||
"""Retrieve a resource's header
|
||||
|
||||
:param resource_type: The type of resource to retrieve.
|
||||
:type resource_type: :class:`~openstack.resource.Resource`
|
||||
:param value: The value of a specific resource to retreive headers
|
||||
for. Can be either the ID of a resource,
|
||||
a :class:`~openstack.resource.Resource` subclass,
|
||||
or ``None``.
|
||||
:param path_args: A dict containing arguments for forming the request
|
||||
URL, if needed.
|
||||
|
||||
:returns: The result of the ``head`` call
|
||||
:rtype: :class:`~openstack.resource.Resource`
|
||||
"""
|
||||
res = self._get_resource(resource_type, value, path_args)
|
||||
|
||||
return res.head(self)
|
||||
|
||||
def wait_for_status(self, value, status, failures=None, interval=2,
|
||||
wait=120):
|
||||
"""Wait for a resource to be in a particular status.
|
||||
|
||||
:param value: The resource to wait on to reach the status. The
|
||||
resource must have a status attribute.
|
||||
:type value: :class:`~openstack.resource.Resource`
|
||||
:param status: Desired status of the resource.
|
||||
:param list failures: Statuses that would indicate the transition
|
||||
failed such as 'ERROR'.
|
||||
:param interval: Number of seconds to wait between checks.
|
||||
:param wait: Maximum number of seconds to wait for the change.
|
||||
|
||||
:return: Method returns resource on success.
|
||||
:raises: :class:`~openstack.exceptions.ResourceTimeout` transition
|
||||
to status failed to occur in wait seconds.
|
||||
:raises: :class:`~openstack.exceptions.ResourceFailure` resource
|
||||
transitioned to one of the failure states.
|
||||
:raises: :class:`~AttributeError` if the resource does not have a
|
||||
status attribute
|
||||
"""
|
||||
failures = [] if failures is None else failures
|
||||
return resource.wait_for_status(self, value, status,
|
||||
failures, interval, wait)
|
||||
|
||||
def wait_for_delete(self, value, interval=2, wait=120):
|
||||
"""Wait for the resource to be deleted.
|
||||
|
||||
:param value: The resource to wait on to be deleted.
|
||||
:type value: :class:`~openstack.resource.Resource`
|
||||
:param interval: Number of seconds to wait between checks.
|
||||
:param wait: Maximum number of seconds to wait for the delete.
|
||||
|
||||
:return: Method returns resource on success.
|
||||
:raises: :class:`~openstack.exceptions.ResourceTimeout` transition
|
||||
to delete failed to occur in wait seconds.
|
||||
"""
|
||||
return resource.wait_for_delete(self, value, interval, wait)
|
File diff suppressed because it is too large
Load Diff
@ -22,7 +22,6 @@ import warnings
|
||||
import os_service_types
|
||||
|
||||
from openstack import _log
|
||||
from openstack import proxy
|
||||
from openstack import proxy2
|
||||
|
||||
_logger = _log.setup_logging('openstack')
|
||||
@ -97,17 +96,11 @@ class ServiceDescription(object):
|
||||
self._validate_proxy_class()
|
||||
|
||||
def _validate_proxy_class(self):
|
||||
if not issubclass(
|
||||
self.proxy_class, (proxy.BaseProxy, proxy2.BaseProxy)):
|
||||
if not issubclass(self.proxy_class, proxy2.BaseProxy):
|
||||
raise TypeError(
|
||||
"{module}.{proxy_class} must inherit from BaseProxy".format(
|
||||
module=self.proxy_class.__module__,
|
||||
proxy_class=self.proxy_class.__name__))
|
||||
if issubclass(self.proxy_class, proxy.BaseProxy) and self._warn_if_old:
|
||||
warnings.warn(
|
||||
"Use of proxy.BaseProxy is not supported."
|
||||
" Please update to use proxy2.BaseProxy.",
|
||||
DeprecationWarning)
|
||||
|
||||
|
||||
class OpenStackServiceDescription(ServiceDescription):
|
||||
|
@ -1,358 +0,0 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from openstack import exceptions
|
||||
from openstack import proxy
|
||||
from openstack import resource
|
||||
|
||||
|
||||
class DeleteableResource(resource.Resource):
|
||||
allow_delete = True
|
||||
|
||||
|
||||
class UpdateableResource(resource.Resource):
|
||||
allow_update = True
|
||||
|
||||
|
||||
class CreateableResource(resource.Resource):
|
||||
allow_create = True
|
||||
|
||||
|
||||
class RetrieveableResource(resource.Resource):
|
||||
allow_retrieve = True
|
||||
|
||||
|
||||
class ListableResource(resource.Resource):
|
||||
allow_list = True
|
||||
|
||||
|
||||
class HeadableResource(resource.Resource):
|
||||
allow_head = True
|
||||
|
||||
|
||||
class Test_check_resource(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(Test_check_resource, self).setUp()
|
||||
|
||||
def method(self, expected_type, value):
|
||||
return value
|
||||
|
||||
self.sot = mock.Mock()
|
||||
self.sot.method = method
|
||||
|
||||
def _test_correct(self, value):
|
||||
decorated = proxy._check_resource(strict=False)(self.sot.method)
|
||||
rv = decorated(self.sot, resource.Resource, value)
|
||||
|
||||
self.assertEqual(value, rv)
|
||||
|
||||
def test_correct_resource(self):
|
||||
res = resource.Resource()
|
||||
self._test_correct(res)
|
||||
|
||||
def test_notstrict_id(self):
|
||||
self._test_correct("abc123-id")
|
||||
|
||||
def test_strict_id(self):
|
||||
decorated = proxy._check_resource(strict=True)(self.sot.method)
|
||||
self.assertRaisesRegex(ValueError, "A Resource must be passed",
|
||||
decorated, self.sot, resource.Resource,
|
||||
"this-is-not-a-resource")
|
||||
|
||||
def test_incorrect_resource(self):
|
||||
class OneType(resource.Resource):
|
||||
pass
|
||||
|
||||
class AnotherType(resource.Resource):
|
||||
pass
|
||||
|
||||
value = AnotherType()
|
||||
decorated = proxy._check_resource(strict=False)(self.sot.method)
|
||||
self.assertRaisesRegex(ValueError,
|
||||
"Expected OneType but received AnotherType",
|
||||
decorated, self.sot, OneType, value)
|
||||
|
||||
|
||||
class TestProxyDelete(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestProxyDelete, self).setUp()
|
||||
|
||||
self.session = mock.Mock()
|
||||
|
||||
self.fake_id = 1
|
||||
self.res = mock.Mock(spec=DeleteableResource)
|
||||
self.res.id = self.fake_id
|
||||
self.res.delete = mock.Mock()
|
||||
|
||||
self.sot = proxy.BaseProxy(self.session)
|
||||
DeleteableResource.existing = mock.Mock(return_value=self.res)
|
||||
|
||||
def test_delete(self):
|
||||
self.sot._delete(DeleteableResource, self.res)
|
||||
self.res.delete.assert_called_with(self.sot, error_message=mock.ANY)
|
||||
|
||||
self.sot._delete(DeleteableResource, self.fake_id)
|
||||
DeleteableResource.existing.assert_called_with(id=self.fake_id)
|
||||
self.res.delete.assert_called_with(self.sot, error_message=mock.ANY)
|
||||
|
||||
# Delete generally doesn't return anything, so we will normally
|
||||
# swallow any return from within a service's proxy, but make sure
|
||||
# we can still return for any cases where values are returned.
|
||||
self.res.delete.return_value = self.fake_id
|
||||
rv = self.sot._delete(DeleteableResource, self.fake_id)
|
||||
self.assertEqual(rv, self.fake_id)
|
||||
|
||||
def test_delete_ignore_missing(self):
|
||||
self.res.delete.side_effect = exceptions.NotFoundException(
|
||||
message="test", http_status=404)
|
||||
|
||||
rv = self.sot._delete(DeleteableResource, self.fake_id)
|
||||
self.assertIsNone(rv)
|
||||
|
||||
def test_delete_NotFound(self):
|
||||
self.res.delete.side_effect = exceptions.NotFoundException(
|
||||
message="test", http_status=404)
|
||||
|
||||
self.assertRaisesRegex(
|
||||
exceptions.NotFoundException, "test",
|
||||
self.sot._delete, DeleteableResource, self.res,
|
||||
ignore_missing=False)
|
||||
|
||||
def test_delete_HttpException(self):
|
||||
self.res.delete.side_effect = exceptions.HttpException(
|
||||
message="test", http_status=500)
|
||||
|
||||
self.assertRaises(exceptions.HttpException, self.sot._delete,
|
||||
DeleteableResource, self.res, ignore_missing=False)
|
||||
|
||||
|
||||
class TestProxyUpdate(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestProxyUpdate, self).setUp()
|
||||
|
||||
self.session = mock.Mock()
|
||||
|
||||
self.fake_id = 1
|
||||
self.fake_result = "fake_result"
|
||||
|
||||
self.res = mock.Mock(spec=UpdateableResource)
|
||||
self.res.update = mock.Mock(return_value=self.fake_result)
|
||||
self.res.update_attrs = mock.Mock()
|
||||
|
||||
self.sot = proxy.BaseProxy(self.session)
|
||||
|
||||
self.attrs = {"x": 1, "y": 2, "z": 3}
|
||||
|
||||
UpdateableResource.existing = mock.Mock(return_value=self.res)
|
||||
|
||||
def _test_update(self, value):
|
||||
rv = self.sot._update(UpdateableResource, value, **self.attrs)
|
||||
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
self.res.update_attrs.assert_called_once_with(self.attrs)
|
||||
self.res.update.assert_called_once_with(self.sot)
|
||||
|
||||
def test_update_resource(self):
|
||||
self._test_update(self.res)
|
||||
|
||||
def test_update_id(self):
|
||||
self._test_update(self.fake_id)
|
||||
|
||||
|
||||
class TestProxyCreate(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestProxyCreate, self).setUp()
|
||||
|
||||
self.session = mock.Mock()
|
||||
|
||||
self.fake_result = "fake_result"
|
||||
self.res = mock.Mock(spec=CreateableResource)
|
||||
self.res.create = mock.Mock(return_value=self.fake_result)
|
||||
|
||||
self.sot = proxy.BaseProxy(self.session)
|
||||
|
||||
def test_create_attributes(self):
|
||||
CreateableResource.new = mock.Mock(return_value=self.res)
|
||||
|
||||
attrs = {"x": 1, "y": 2, "z": 3}
|
||||
rv = self.sot._create(CreateableResource, **attrs)
|
||||
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
CreateableResource.new.assert_called_once_with(**attrs)
|
||||
self.res.create.assert_called_once_with(self.sot)
|
||||
|
||||
|
||||
class TestProxyGet(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestProxyGet, self).setUp()
|
||||
|
||||
self.session = mock.Mock()
|
||||
|
||||
self.fake_id = 1
|
||||
self.fake_name = "fake_name"
|
||||
self.fake_result = "fake_result"
|
||||
self.res = mock.Mock(spec=RetrieveableResource)
|
||||
self.res.id = self.fake_id
|
||||
self.res.get = mock.Mock(return_value=self.fake_result)
|
||||
|
||||
self.sot = proxy.BaseProxy(self.session)
|
||||
RetrieveableResource.existing = mock.Mock(return_value=self.res)
|
||||
|
||||
def test_get_resource(self):
|
||||
rv = self.sot._get(RetrieveableResource, self.res)
|
||||
|
||||
self.res.get.assert_called_with(self.sot, args=None,
|
||||
error_message=mock.ANY)
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
|
||||
def test_get_resource_with_args(self):
|
||||
rv = self.sot._get(RetrieveableResource, self.res, args={'K': 'V'})
|
||||
|
||||
self.res.get.assert_called_with(
|
||||
self.sot, args={'K': 'V'},
|
||||
error_message='No RetrieveableResource found for {res}'.format(
|
||||
res=str(self.res)))
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
|
||||
def test_get_id(self):
|
||||
rv = self.sot._get(RetrieveableResource, self.fake_id)
|
||||
|
||||
RetrieveableResource.existing.assert_called_with(id=self.fake_id)
|
||||
self.res.get.assert_called_with(self.sot, args=None,
|
||||
error_message=mock.ANY)
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
|
||||
def test_get_not_found(self):
|
||||
self.res.get.side_effect = exceptions.NotFoundException(
|
||||
message="test", http_status=404)
|
||||
|
||||
# TODO(shade) The mock here does not mock the right things, so we're
|
||||
# not testing the actual exception mechanism.
|
||||
self.assertRaisesRegex(
|
||||
exceptions.NotFoundException, "test",
|
||||
self.sot._get, RetrieveableResource, self.res)
|
||||
|
||||
|
||||
class TestProxyList(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestProxyList, self).setUp()
|
||||
|
||||
self.session = mock.Mock()
|
||||
|
||||
self.fake_a = 1
|
||||
self.fake_b = 2
|
||||
self.fake_c = 3
|
||||
self.fake_resource = resource.Resource.new(id=self.fake_a)
|
||||
self.fake_response = [resource.Resource()]
|
||||
self.fake_query = {"a": self.fake_resource, "b": self.fake_b}
|
||||
self.fake_path_args = {"c": self.fake_c}
|
||||
|
||||
self.sot = proxy.BaseProxy(self.session)
|
||||
ListableResource.list = mock.Mock()
|
||||
ListableResource.list.return_value = self.fake_response
|
||||
|
||||
def _test_list(self, path_args, paginated, **query):
|
||||
rv = self.sot._list(ListableResource, path_args=path_args,
|
||||
paginated=paginated, **query)
|
||||
|
||||
self.assertEqual(self.fake_response, rv)
|
||||
ListableResource.list.assert_called_once_with(
|
||||
self.sot, path_args=path_args, paginated=paginated,
|
||||
params={'a': self.fake_a, 'b': self.fake_b})
|
||||
|
||||
def test_list_paginated(self):
|
||||
self._test_list(self.fake_path_args, True, **self.fake_query)
|
||||
|
||||
def test_list_non_paginated(self):
|
||||
self._test_list(self.fake_path_args, False, **self.fake_query)
|
||||
|
||||
|
||||
class TestProxyHead(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestProxyHead, self).setUp()
|
||||
|
||||
self.session = mock.Mock()
|
||||
|
||||
self.fake_id = 1
|
||||
self.fake_name = "fake_name"
|
||||
self.fake_result = "fake_result"
|
||||
self.res = mock.Mock(spec=HeadableResource)
|
||||
self.res.id = self.fake_id
|
||||
self.res.head = mock.Mock(return_value=self.fake_result)
|
||||
|
||||
self.sot = proxy.BaseProxy(self.session)
|
||||
HeadableResource.existing = mock.Mock(return_value=self.res)
|
||||
|
||||
def test_head_resource(self):
|
||||
rv = self.sot._head(HeadableResource, self.res)
|
||||
|
||||
self.res.head.assert_called_with(self.sot)
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
|
||||
def test_head_id(self):
|
||||
rv = self.sot._head(HeadableResource, self.fake_id)
|
||||
|
||||
HeadableResource.existing.assert_called_with(id=self.fake_id)
|
||||
self.res.head.assert_called_with(self.sot)
|
||||
self.assertEqual(rv, self.fake_result)
|
||||
|
||||
def test_head_no_value(self):
|
||||
MockHeadResource = mock.Mock(spec=HeadableResource)
|
||||
instance = mock.Mock()
|
||||
MockHeadResource.return_value = instance
|
||||
|
||||
self.sot._head(MockHeadResource)
|
||||
|
||||
MockHeadResource.assert_called_with()
|
||||
instance.head.assert_called_with(self.sot)
|
||||
|
||||
@mock.patch("openstack.resource.wait_for_status")
|
||||
def test_wait_for(self, mock_wait):
|
||||
mock_resource = mock.Mock()
|
||||
mock_wait.return_value = mock_resource
|
||||
self.sot.wait_for_status(mock_resource, 'ACTIVE')
|
||||
mock_wait.assert_called_once_with(
|
||||
self.sot, mock_resource, 'ACTIVE', [], 2, 120)
|
||||
|
||||
@mock.patch("openstack.resource.wait_for_status")
|
||||
def test_wait_for_params(self, mock_wait):
|
||||
mock_resource = mock.Mock()
|
||||
mock_wait.return_value = mock_resource
|
||||
self.sot.wait_for_status(mock_resource, 'ACTIVE', ['ERROR'], 1, 2)
|
||||
mock_wait.assert_called_once_with(
|
||||
self.sot, mock_resource, 'ACTIVE', ['ERROR'], 1, 2)
|
||||
|
||||
@mock.patch("openstack.resource.wait_for_delete")
|
||||
def test_wait_for_delete(self, mock_wait):
|
||||
mock_resource = mock.Mock()
|
||||
mock_wait.return_value = mock_resource
|
||||
self.sot.wait_for_delete(mock_resource)
|
||||
mock_wait.assert_called_once_with(
|
||||
self.sot, mock_resource, 2, 120)
|
||||
|
||||
@mock.patch("openstack.resource.wait_for_delete")
|
||||
def test_wait_for_delete_params(self, mock_wait):
|
||||
mock_resource = mock.Mock()
|
||||
mock_wait.return_value = mock_resource
|
||||
self.sot.wait_for_delete(mock_resource, 1, 2)
|
||||
mock_wait.assert_called_once_with(
|
||||
self.sot, mock_resource, 1, 2)
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user