From 1f6990edbf31096f7d0c82dabb9a16c1b99af575 Mon Sep 17 00:00:00 2001 From: Everett Toews Date: Sun, 28 Feb 2016 14:07:00 -0600 Subject: [PATCH] Make metadata handling consistent in Compute Make metadata handling consistent across all Compute resources. The consistent methods are get_*_metdata, set_*_metadata, and delete_*_metadata which is similar to the __get__, __set__, and __delete__ methods of a descriptor or the __getitem__, __setitem__, and __delitem__ of a MutableMapping so it should be fairly natural for Python users. Change-Id: I977e8741bdd755e8af8c0f3c4e16e38cfba79bd5 Closes-Bug: #1546156 --- openstack/compute/v2/_proxy.py | 148 +++++------------- openstack/compute/v2/metadata.py | 71 ++------- openstack/compute/v2/server_meta.py | 76 --------- openstack/compute/v2/server_metadata.py | 53 ------- .../tests/functional/compute/v2/test_image.py | 77 +++++---- .../functional/compute/v2/test_server.py | 83 +++++----- .../tests/unit/compute/v2/test_metadata.py | 100 +----------- openstack/tests/unit/compute/v2/test_proxy.py | 46 ++---- .../tests/unit/compute/v2/test_server_meta.py | 137 ---------------- .../unit/compute/v2/test_server_metadata.py | 97 ------------ openstack/tests/unit/test_proxy_base.py | 10 +- 11 files changed, 171 insertions(+), 727 deletions(-) delete mode 100644 openstack/compute/v2/server_meta.py delete mode 100644 openstack/compute/v2/server_metadata.py delete mode 100644 openstack/tests/unit/compute/v2/test_server_meta.py delete mode 100644 openstack/tests/unit/compute/v2/test_server_metadata.py diff --git a/openstack/compute/v2/_proxy.py b/openstack/compute/v2/_proxy.py index 9b8970db..a0e59056 100644 --- a/openstack/compute/v2/_proxy.py +++ b/openstack/compute/v2/_proxy.py @@ -198,64 +198,27 @@ class Proxy(proxy.BaseProxy): else: return base({"id": res}) - def get_image_metadata(self, image, key=None): + def get_image_metadata(self, image): """Return a dictionary of metadata for an image - :param server: Either the ID of an image or a + :param image: Either the ID of an image or a :class:`~openstack.compute.v2.image.Image` or :class:`~openstack.compute.v2.image.ImageDetail` instance. - :param key: An optional key to retrieve from the image's metadata. - When no ``key`` is specified, all metadata is retrieved. - :returns: A dictionary of the image's metadata. All keys and values - are Unicode text. - :rtype: dict + :returns: A :class:`~openstack.compute.v2.image.Image` with only the + image's metadata. All keys and values are Unicode text. + :rtype: :class:`~openstack.compute.v2.image.Image` """ res = self._get_base_resource(image, _image.Image) - return res.get_metadata(self.session, key) + metadata = res.get_metadata(self.session) + result = _image.Image.existing(id=res.id, metadata=metadata) + return result - def create_image_metadata(self, image, **metadata): - """Create metadata for an image - - :param server: Either the ID of an image or a - :class:`~openstack.compute.v2.image.Image` or - :class:`~openstack.compute.v2.image.ImageDetail` - instance. - :param kwargs metadata: Key/value pairs to be added as metadata - on the image. All keys and values - are stored as Unicode. - - :returns: A dictionary of the metadata that was created on the image. - All keys and values are Unicode text. - :rtype: dict - """ - res = self._get_base_resource(image, _image.Image) - return res.create_metadata(self.session, **metadata) - - def replace_image_metadata(self, image, **metadata): - """Replace metadata for an image - - :param server: Either the ID of a image or a - :class:`~openstack.compute.v2.image.Image` or - :class:`~openstack.compute.v2.image.ImageDetail` - instance. - :param kwargs metadata: Key/value pairs to be added as metadata - on the image. Any other existing metadata - is removed. All keys and values are stored - as Unicode. - - :returns: A dictionary of the metadata for the image. All keys and - values are Unicode text. - :rtype: dict - """ - res = self._get_base_resource(image, _image.Image) - return res.replace_metadata(self.session, **metadata) - - def update_image_metadata(self, image, **metadata): + def set_image_metadata(self, image, **metadata): """Update metadata for an image - :param server: Either the ID of an image or a + :param image: Either the ID of an image or a :class:`~openstack.compute.v2.image.Image` or :class:`~openstack.compute.v2.image.ImageDetail` instance. @@ -264,26 +227,30 @@ class Proxy(proxy.BaseProxy): by this call. All keys and values are stored as Unicode. - :returns: A dictionary of the metadata for the image. All keys and - values are Unicode text. - :rtype: dict + :returns: A :class:`~openstack.compute.v2.image.Image` with only the + image's metadata. All keys and values are Unicode text. + :rtype: :class:`~openstack.compute.v2.image.Image` """ res = self._get_base_resource(image, _image.Image) - return res.update_metadata(self.session, **metadata) + metadata = res.set_metadata(self.session, **metadata) + result = _image.Image.existing(id=res.id, metadata=metadata) + return result - def delete_image_metadata(self, image, key): + def delete_image_metadata(self, image, keys): """Delete metadata for an image - :param server: Either the ID of an image or a + Note: This method will do a HTTP DELETE request for every key in keys. + + :param image: Either the ID of an image or a :class:`~openstack.compute.v2.image.Image` or :class:`~openstack.compute.v2.image.ImageDetail` instance. - :param key: The key to delete + :param list keys: The keys to delete. :rtype: ``None`` """ res = self._get_base_resource(image, _image.Image) - return res.delete_metadata(self.session, key) + return res.delete_metadata(self.session, keys) def create_keypair(self, **attrs): """Create a new keypair from attributes @@ -681,61 +648,24 @@ class Proxy(proxy.BaseProxy): return self._list(availability_zone.AvailabilityZone, paginated=False, **query) - def get_server_metadata(self, server, key=None): + def get_server_metadata(self, server): """Return a dictionary of metadata for a server :param server: Either the ID of a server or a :class:`~openstack.compute.v2.server.Server` or :class:`~openstack.compute.v2.server.ServerDetail` instance. - :param key: An optional key to retrieve from the server's metadata. - When no ``key`` is specified, all metadata is retrieved. - :returns: A dictionary of the server's metadata. All keys and values - are Unicode text. - :rtype: dict + :returns: A :class:`~openstack.compute.v2.server.Server` with only the + server's metadata. All keys and values are Unicode text. + :rtype: :class:`~openstack.compute.v2.server.Server` """ res = self._get_base_resource(server, _server.Server) - return res.get_metadata(self.session, key) + metadata = res.get_metadata(self.session) + result = _server.Server.existing(id=res.id, metadata=metadata) + return result - def create_server_metadata(self, server, **metadata): - """Create metadata for a server - - :param server: Either the ID of a server or a - :class:`~openstack.compute.v2.server.Server` or - :class:`~openstack.compute.v2.server.ServerDetail` - instance. - :param kwargs metadata: Key/value pairs to be added as metadata - on the server. All keys and values - are stored as Unicode. - - :returns: A dictionary of the metadata that was created on the server. - All keys and values are Unicode text. - :rtype: dict - """ - res = self._get_base_resource(server, _server.Server) - return res.create_metadata(self.session, **metadata) - - def replace_server_metadata(self, server, **metadata): - """Replace metadata for a server - - :param server: Either the ID of a server or a - :class:`~openstack.compute.v2.server.Server` or - :class:`~openstack.compute.v2.server.ServerDetail` - instance. - :param kwargs metadata: Key/value pairs to be added as metadata - on the server. Any other existing metadata - is removed. All keys and values are stored - as Unicode. - - :returns: A dictionary of the metadata for the server. All keys and - values are Unicode text. - :rtype: dict - """ - res = self._get_base_resource(server, _server.Server) - return res.replace_metadata(self.session, **metadata) - - def update_server_metadata(self, server, **metadata): + def set_server_metadata(self, server, **metadata): """Update metadata for a server :param server: Either the ID of a server or a @@ -747,26 +677,30 @@ class Proxy(proxy.BaseProxy): by this call. All keys and values are stored as Unicode. - :returns: A dictionary of the metadata for the server. All keys and - values are Unicode text. - :rtype: dict + :returns: A :class:`~openstack.compute.v2.server.Server` with only the + server's metadata. All keys and values are Unicode text. + :rtype: :class:`~openstack.compute.v2.server.Server` """ res = self._get_base_resource(server, _server.Server) - return res.update_metadata(self.session, **metadata) + metadata = res.set_metadata(self.session, **metadata) + result = _server.Server.existing(id=res.id, metadata=metadata) + return result - def delete_server_metadata(self, server, key): + def delete_server_metadata(self, server, keys): """Delete metadata for a server + Note: This method will do a HTTP DELETE request for every key in keys. + :param server: Either the ID of a server or a :class:`~openstack.compute.v2.server.Server` or :class:`~openstack.compute.v2.server.ServerDetail` instance. - :param key: The key to delete + :param list keys: The keys to delete :rtype: ``None`` """ res = self._get_base_resource(server, _server.Server) - return res.delete_metadata(self.session, key) + return res.delete_metadata(self.session, keys) def create_server_group(self, **attrs): """Create a new server group from attributes diff --git a/openstack/compute/v2/metadata.py b/openstack/compute/v2/metadata.py index 783f6c66..e611fd98 100644 --- a/openstack/compute/v2/metadata.py +++ b/openstack/compute/v2/metadata.py @@ -39,7 +39,7 @@ class MetadataMixin(object): kwargs = {"endpoint_filter": self.service} if metadata or clear: - # 'meta' is the key for singlular modifications. + # 'meta' is the key for singular modifications. # 'metadata' is the key for mass modifications. key = "meta" if key is not None else "metadata" kwargs["json"] = {key: metadata} @@ -51,70 +51,19 @@ class MetadataMixin(object): # DELETE doesn't return a JSON body while everything else does. return response.json() if not delete else None - def get_metadata(self, session, key=None): + def get_metadata(self, session): """Retrieve metadata :param session: The session to use for this request. - :param key: If specified, retrieve metadata only for this key. - If not specified, or ``None`` (the default), - retrieve all available metadata. :returns: A dictionary of the requested metadata. All keys and values are Unicode text. :rtype: dict """ - result = self._metadata(session.get, key=key) - return result["metadata"] if key is None else result["meta"] - - def create_metadata(self, session, **metadata): - """Create metadata - - NOTE: One PUT call will be made for each key/value pair specified. - - :param session: The session to use for this request. - :param kwargs metadata: key/value metadata pairs to be created on - this server instance. All keys and values - are stored as Unicode. - - :returns: A dictionary of the metadata that was created. All keys and - values are Unicode text. - :rtype: dict - """ - results = {} - # A PUT to /metadata will entirely replace any existing metadata, - # so we need to PUT each individual key/value to /metadata/key - # in order to preserve anything existing and only add new keys. - for key, value in metadata.items(): - result = self._metadata(session.put, key=key, **{key: value}) - results[key] = result["meta"][key] - return results - - def replace_metadata(self, session, **metadata): - """Replace metadata - - This call will replace any existing metadata with the key/value pairs - given here. - - :param session: The session to use for this request. - :param kwargs metadata: key/value metadata pairs to be created on - this server instance. Any other existing - metadata is removed. - When metadata is not set, it is effectively - cleared out, replacing the metadata - with nothing. - All keys and values are stored as Unicode. - - - :returns: A dictionary of the metadata after being replaced. - All keys and values are Unicode text. - :rtype: dict - """ - # A PUT with empty metadata will clear anything out. - clear = True if not metadata else False - result = self._metadata(session.put, clear=clear, **metadata) + result = self._metadata(session.get) return result["metadata"] - def update_metadata(self, session, **metadata): + def set_metadata(self, session, **metadata): """Update metadata This call will replace only the metadata with the same keys @@ -129,15 +78,21 @@ class MetadataMixin(object): All keys and values are Unicode text. :rtype: dict """ + if not metadata: + return dict() + result = self._metadata(session.post, **metadata) return result["metadata"] - def delete_metadata(self, session, key): + def delete_metadata(self, session, keys): """Delete metadata + Note: This method will do a HTTP DELETE request for every key in keys. + :param session: The session to use for this request. - :param string key: The key to delete. + :param list keys: The keys to delete. :rtype: ``None`` """ - self._metadata(session.delete, key=key, delete=True) + for key in keys: + self._metadata(session.delete, key=key, delete=True) diff --git a/openstack/compute/v2/server_meta.py b/openstack/compute/v2/server_meta.py deleted file mode 100644 index 0377beb6..00000000 --- a/openstack/compute/v2/server_meta.py +++ /dev/null @@ -1,76 +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 six - -from openstack.compute import compute_service -from openstack import resource - - -class ServerMeta(resource.Resource): - resource_key = 'meta' - id_attribute = 'key' - base_path = '/servers/%(server_id)s/metadata' - service = compute_service.ComputeService() - - # capabilities - allow_create = True - allow_retrieve = True - allow_update = True - allow_delete = True - allow_list = True - - # Properties - #: The metadata key. - key = resource.prop('key') - #: The ID of a server. - server_id = resource.prop('server_id') - #: The metadata value. - value = resource.prop('value') - - @classmethod - def create_by_id(cls, session, attrs, resource_id=None, path_args=None): - url = cls._get_url(path_args, resource_id) - body = {cls.resource_key: {attrs['key']: attrs['value']}} - resp = session.put(url, endpoint_filter=cls.service, json=body) - resp = resp.json() - return {'key': resource_id, - 'value': resp[cls.resource_key][resource_id]} - - @classmethod - def get_data_by_id(cls, session, resource_id, path_args=None, - include_headers=False): - url = cls._get_url(path_args, resource_id) - resp = session.get(url, endpoint_filter=cls.service) - resp = resp.json() - return {'key': resource_id, - 'value': resp[cls.resource_key][resource_id]} - - @classmethod - def update_by_id(cls, session, resource_id, attrs, path_args=None): - return cls.create_by_id(session, attrs, resource_id, path_args) - - @classmethod - def delete_by_id(cls, session, resource_id, path_args=None): - url = cls._get_url(path_args, resource_id) - headers = {'Accept': ''} - session.delete(url, endpoint_filter=cls.service, headers=headers) - - @classmethod - def list(cls, session, path_args=None, **params): - url = '/servers/%(server_id)s/metadata' % path_args - resp = session.get(url, endpoint_filter=cls.service, params=params) - resp = resp.json() - resp = resp['metadata'] - return [cls.existing(server_id=path_args['server_id'], key=key, - value=value) - for key, value in six.iteritems(resp)] diff --git a/openstack/compute/v2/server_metadata.py b/openstack/compute/v2/server_metadata.py deleted file mode 100644 index c243e18c..00000000 --- a/openstack/compute/v2/server_metadata.py +++ /dev/null @@ -1,53 +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.compute import compute_service -from openstack import resource - - -class ServerMetadata(resource.Resource): - resource_key = 'metadata' - id_attribute = 'server_id' - base_path = '/servers/%(server_id)s/metadata' - service = compute_service.ComputeService() - - # capabilities - allow_create = True - allow_retrieve = True - allow_update = True - - # Properties - #: The ID of a server. - server_id = resource.prop('server_id') - - @classmethod - def create_by_id(cls, session, attrs, resource_id=None, path_args=None): - no_id = attrs.copy() - no_id.pop('server_id') - body = {"metadata": no_id} - url = cls._get_url(path_args) - resp = session.put(url, endpoint_filter=cls.service, json=body) - resp = resp.json() - attrs = resp["metadata"].copy() - attrs['server_id'] = resource_id - return attrs - - @classmethod - def get_data_by_id(cls, session, resource_id, path_args=None, args=None, - include_headers=False): - url = cls._get_url(path_args) - resp = session.get(url, endpoint_filter=cls.service) - return resp.json()[cls.resource_key] - - @classmethod - def update_by_id(cls, session, resource_id, attrs, path_args=None): - return cls.create_by_id(session, attrs, resource_id, path_args) diff --git a/openstack/tests/functional/compute/v2/test_image.py b/openstack/tests/functional/compute/v2/test_image.py index 687537fb..79200bfa 100644 --- a/openstack/tests/functional/compute/v2/test_image.py +++ b/openstack/tests/functional/compute/v2/test_image.py @@ -55,40 +55,55 @@ class TestImage(base.BaseFunctionalTest): def test_image_metadata(self): image = self._get_non_test_image() - sot = self.conn.compute.get_image(image.id) - # Start by clearing out any other metadata. - self.assertDictEqual(self.conn.compute.replace_image_metadata(sot), - {}) + # delete pre-existing metadata + self.conn.compute.delete_image_metadata(image, image.metadata.keys()) + image = self.conn.compute.get_image_metadata(image) + self.assertFalse(image.metadata) - # Insert first and last name metadata - meta = {"first": "Matthew", "last": "Dellavedova"} - self.assertDictEqual( - self.conn.compute.create_image_metadata(sot, **meta), meta) + # get metadata + image = self.conn.compute.get_image_metadata(image) + self.assertFalse(image.metadata) - # Update only the first name - short = {"first": "Matt", "last": "Dellavedova"} - self.assertDictEqual( - self.conn.compute.update_image_metadata(sot, - first=short["first"]), - short) + # set no metadata + self.conn.compute.set_image_metadata(image) + image = self.conn.compute.get_image_metadata(image) + self.assertFalse(image.metadata) - # Get all metadata and then only the last name - self.assertDictEqual(self.conn.compute.get_image_metadata(sot), - short) - self.assertDictEqual( - self.conn.compute.get_image_metadata(sot, "last"), - {"last": short["last"]}) + # set empty metadata + self.conn.compute.set_image_metadata(image, k0='') + image = self.conn.compute.get_image_metadata(image) + self.assertFalse(image.metadata) - # Replace everything with just a nickname - nick = {"nickname": "Delly"} - self.assertDictEqual( - self.conn.compute.replace_image_metadata(sot, **nick), - nick) - self.assertDictEqual(self.conn.compute.get_image_metadata(sot), - nick) + # set metadata + self.conn.compute.set_image_metadata(image, k1='v1') + image = self.conn.compute.get_image_metadata(image) + self.assertTrue(image.metadata) + self.assertEqual(1, len(image.metadata)) + self.assertIn('k1', image.metadata) + self.assertEqual('v1', image.metadata['k1']) - # Delete the only remaining key, make sure we're empty - self.assertIsNone( - self.conn.compute.delete_image_metadata(sot, "nickname")) - self.assertDictEqual(self.conn.compute.get_image_metadata(sot), {}) + # set more metadata + self.conn.compute.set_image_metadata(image, k2='v2') + image = self.conn.compute.get_image_metadata(image) + self.assertTrue(image.metadata) + self.assertEqual(2, len(image.metadata)) + self.assertIn('k1', image.metadata) + self.assertEqual('v1', image.metadata['k1']) + self.assertIn('k2', image.metadata) + self.assertEqual('v2', image.metadata['k2']) + + # update metadata + self.conn.compute.set_image_metadata(image, k1='v1.1') + image = self.conn.compute.get_image_metadata(image) + self.assertTrue(image.metadata) + self.assertEqual(2, len(image.metadata)) + self.assertIn('k1', image.metadata) + self.assertEqual('v1.1', image.metadata['k1']) + self.assertIn('k2', image.metadata) + self.assertEqual('v2', image.metadata['k2']) + + # delete metadata + self.conn.compute.delete_image_metadata(image, image.metadata.keys()) + image = self.conn.compute.get_image_metadata(image) + self.assertFalse(image.metadata) diff --git a/openstack/tests/functional/compute/v2/test_server.py b/openstack/tests/functional/compute/v2/test_server.py index e187287a..a88dd0af 100644 --- a/openstack/tests/functional/compute/v2/test_server.py +++ b/openstack/tests/functional/compute/v2/test_server.py @@ -69,45 +69,58 @@ class TestServer(base.BaseFunctionalTest): self.assertIn(self.NAME, names) def test_server_metadata(self): - sot = self.conn.compute.get_server(self.server.id) + test_server = self.conn.compute.get_server(self.server.id) - # Start by clearing out any other metadata. - self.assertDictEqual(self.conn.compute.replace_server_metadata(sot), - {}) + # get metadata + test_server = self.conn.compute.get_server_metadata(test_server) + self.assertFalse(test_server.metadata) - # Create first and last name metadata - meta = {"first": "Matthew", "last": "Dellavedova"} - self.assertDictEqual( - self.conn.compute.create_server_metadata(sot, **meta), meta) + # set no metadata + self.conn.compute.set_server_metadata(test_server) + test_server = self.conn.compute.get_server_metadata(test_server) + self.assertFalse(test_server.metadata) - # Create something that already exists - meta = {"last": "Inman"} - self.assertDictEqual( - self.conn.compute.create_server_metadata(sot, **meta), meta) + # set empty metadata + self.conn.compute.set_server_metadata(test_server, k0='') + server = self.conn.compute.get_server_metadata(test_server) + self.assertTrue(server.metadata) - # Update only the first name - short = {"first": "Matt", "last": "Inman"} - self.assertDictEqual( - self.conn.compute.update_server_metadata(sot, - first=short["first"]), - short) + # set metadata + self.conn.compute.set_server_metadata(test_server, k1='v1') + test_server = self.conn.compute.get_server_metadata(test_server) + self.assertTrue(test_server.metadata) + self.assertEqual(2, len(test_server.metadata)) + self.assertIn('k0', test_server.metadata) + self.assertEqual('', test_server.metadata['k0']) + self.assertIn('k1', test_server.metadata) + self.assertEqual('v1', test_server.metadata['k1']) - # Get all metadata and then only the last name - self.assertDictEqual(self.conn.compute.get_server_metadata(sot), - short) - self.assertDictEqual( - self.conn.compute.get_server_metadata(sot, "last"), - {"last": short["last"]}) + # set more metadata + self.conn.compute.set_server_metadata(test_server, k2='v2') + test_server = self.conn.compute.get_server_metadata(test_server) + self.assertTrue(test_server.metadata) + self.assertEqual(3, len(test_server.metadata)) + self.assertIn('k0', test_server.metadata) + self.assertEqual('', test_server.metadata['k0']) + self.assertIn('k1', test_server.metadata) + self.assertEqual('v1', test_server.metadata['k1']) + self.assertIn('k2', test_server.metadata) + self.assertEqual('v2', test_server.metadata['k2']) - # Replace everything with just a nickname - nick = {"nickname": "Delly"} - self.assertDictEqual( - self.conn.compute.replace_server_metadata(sot, **nick), - nick) - self.assertDictEqual(self.conn.compute.get_server_metadata(sot), - nick) + # update metadata + self.conn.compute.set_server_metadata(test_server, k1='v1.1') + test_server = self.conn.compute.get_server_metadata(test_server) + self.assertTrue(test_server.metadata) + self.assertEqual(3, len(test_server.metadata)) + self.assertIn('k0', test_server.metadata) + self.assertEqual('', test_server.metadata['k0']) + self.assertIn('k1', test_server.metadata) + self.assertEqual('v1.1', test_server.metadata['k1']) + self.assertIn('k2', test_server.metadata) + self.assertEqual('v2', test_server.metadata['k2']) - # Delete the only remaining key, make sure we're empty - self.assertIsNone( - self.conn.compute.delete_server_metadata(sot, "nickname")) - self.assertDictEqual(self.conn.compute.get_server_metadata(sot), {}) + # delete metadata + self.conn.compute.delete_server_metadata( + test_server, test_server.metadata.keys()) + test_server = self.conn.compute.get_server_metadata(test_server) + self.assertFalse(test_server.metadata) diff --git a/openstack/tests/unit/compute/v2/test_metadata.py b/openstack/tests/unit/compute/v2/test_metadata.py index addaff89..0da6d6e4 100644 --- a/openstack/tests/unit/compute/v2/test_metadata.py +++ b/openstack/tests/unit/compute/v2/test_metadata.py @@ -52,96 +52,7 @@ class TestMetadata(testtools.TestCase): headers={}, endpoint_filter=sot.service) - def test_get_one_metadata(self): - response = mock.Mock() - response.json.return_value = self.meta_result - sess = mock.Mock() - sess.get.return_value = response - - sot = server.Server({"id": IDENTIFIER}) - - key = "lol" - result = sot.get_metadata(sess, key) - - self.assertEqual(result, self.meta_result["meta"]) - sess.get.assert_called_once_with("servers/IDENTIFIER/metadata/" + key, - headers={}, - endpoint_filter=sot.service) - - def test_create_metadata_bad_type(self): - sess = mock.Mock() - sess.put = mock.Mock() - - sot = server.Server({"id": IDENTIFIER}) - self.assertRaises(ValueError, - sot.create_metadata, sess, some_key=True) - - def test_create_metadata(self): - metadata = {"first": "1", "second": "2"} - responses = [] - for key, value in metadata.items(): - response = mock.Mock() - response.json.return_value = {"meta": {key: value}} - responses.append(response) - - sess = mock.Mock() - sess.put.side_effect = responses - - sot = server.Server({"id": IDENTIFIER}) - - result = sot.create_metadata(sess, **metadata) - - self.assertEqual(result, dict([(k, v) for k, v in metadata.items()])) - - # assert_called_with depends on sequence, which doesn't work nicely - # with all of the dictionaries we're working with here. Build up - # our own list of calls and check that they've happend - calls = [] - for key in metadata.keys(): - calls.append(mock.call("servers/IDENTIFIER/metadata/" + key, - endpoint_filter=sot.service, - headers={}, - json={"meta": {key: metadata[key]}})) - - sess.put.assert_has_calls(calls, any_order=True) - - def test_replace_metadata(self): - response = mock.Mock() - response.json.return_value = self.metadata_result - sess = mock.Mock() - sess.put.return_value = response - - sot = server.Server({"id": IDENTIFIER}) - - new_meta = {"lol": "rofl"} - - result = sot.replace_metadata(sess, **new_meta) - - self.assertEqual(result, self.metadata_result["metadata"]) - sess.put.assert_called_once_with("servers/IDENTIFIER/metadata", - endpoint_filter=sot.service, - headers={}, - json={"metadata": new_meta}) - - def test_replace_metadata_clear(self): - empty = {} - - response = mock.Mock() - response.json.return_value = {"metadata": empty} - sess = mock.Mock() - sess.put.return_value = response - - sot = server.Server({"id": IDENTIFIER}) - - result = sot.replace_metadata(sess) - - self.assertEqual(result, empty) - sess.put.assert_called_once_with("servers/IDENTIFIER/metadata", - endpoint_filter=sot.service, - headers={}, - json={"metadata": empty}) - - def test_update_metadata(self): + def test_set_metadata(self): response = mock.Mock() response.json.return_value = self.metadata_result sess = mock.Mock() @@ -149,15 +60,15 @@ class TestMetadata(testtools.TestCase): sot = server.Server({"id": IDENTIFIER}) - updated_meta = {"lol": "rofl"} + set_meta = {"lol": "rofl"} - result = sot.update_metadata(sess, **updated_meta) + result = sot.set_metadata(sess, **set_meta) self.assertEqual(result, self.metadata_result["metadata"]) sess.post.assert_called_once_with("servers/IDENTIFIER/metadata", endpoint_filter=sot.service, headers={}, - json={"metadata": updated_meta}) + json={"metadata": set_meta}) def test_delete_metadata(self): sess = mock.Mock() @@ -167,9 +78,8 @@ class TestMetadata(testtools.TestCase): key = "hey" - result = sot.delete_metadata(sess, key) + sot.delete_metadata(sess, [key]) - self.assertIsNone(result) sess.delete.assert_called_once_with( "servers/IDENTIFIER/metadata/" + key, headers={"Accept": ""}, diff --git a/openstack/tests/unit/compute/v2/test_proxy.py b/openstack/tests/unit/compute/v2/test_proxy.py index 08d0638a..5f9d2758 100644 --- a/openstack/tests/unit/compute/v2/test_proxy.py +++ b/openstack/tests/unit/compute/v2/test_proxy.py @@ -289,47 +289,23 @@ class TestComputeProxy(test_proxy_base.TestProxyBase): def test_get_all_server_metadata(self): self._verify2("openstack.compute.v2.server.Server.get_metadata", self.proxy.get_server_metadata, - expected_result={}, method_args=["value"], - expected_args=[self.session, None]) + method_result=server.Server.existing(id="value", + metadata={}), + expected_args=[self.session], + expected_result={}) - def test_get_one_server_metadata(self): - self._verify2("openstack.compute.v2.server.Server.get_metadata", - self.proxy.get_server_metadata, - expected_result={}, - method_args=["value"], - method_kwargs={"key": "key"}, - expected_args=[self.session, "key"]) - - def test_create_server_metadata(self): + def test_set_server_metadata(self): kwargs = {"a": "1", "b": "2"} - self._verify2("openstack.compute.v2.server.Server.create_metadata", - self.proxy.create_server_metadata, - expected_result={}, + self._verify2("openstack.compute.v2.server.Server.set_metadata", + self.proxy.set_server_metadata, method_args=["value"], method_kwargs=kwargs, + method_result=server.Server.existing(id="value", + metadata=kwargs), expected_args=[self.session], - expected_kwargs=kwargs) - - def test_replace_server_metadata(self): - kwargs = {"a": "1", "b": "2"} - self._verify2("openstack.compute.v2.server.Server.replace_metadata", - self.proxy.replace_server_metadata, - expected_result={}, - method_args=["value"], - method_kwargs=kwargs, - expected_args=[self.session], - expected_kwargs=kwargs) - - def test_update_server_metadata(self): - kwargs = {"a": "1", "b": "2"} - self._verify2("openstack.compute.v2.server.Server.update_metadata", - self.proxy.update_server_metadata, - expected_result={}, - method_args=["value"], - method_kwargs=kwargs, - expected_args=[self.session], - expected_kwargs=kwargs) + expected_kwargs=kwargs, + expected_result=kwargs) def test_delete_server_metadata(self): self._verify2("openstack.compute.v2.server.Server.delete_metadata", diff --git a/openstack/tests/unit/compute/v2/test_server_meta.py b/openstack/tests/unit/compute/v2/test_server_meta.py deleted file mode 100644 index f8242416..00000000 --- a/openstack/tests/unit/compute/v2/test_server_meta.py +++ /dev/null @@ -1,137 +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.compute.v2 import server_meta - -FAKE_KEY = 'cervus' -FAKE_SERVER_ID = 'cervidae' -FAKE_VALUE = 'canadensis' -EXAMPLE = { - 'key': FAKE_KEY, - 'server_id': FAKE_SERVER_ID, - 'value': FAKE_VALUE, -} -FAKE_RESPONSE = {"meta": {FAKE_KEY: FAKE_VALUE}} -FAKE_RESPONSES = {"metadata": {FAKE_KEY: FAKE_VALUE}} - - -class TestServerMeta(testtools.TestCase): - - def test_basic(self): - sot = server_meta.ServerMeta() - self.assertEqual('meta', sot.resource_key) - self.assertIsNone(sot.resources_key) - self.assertEqual('/servers/%(server_id)s/metadata', sot.base_path) - self.assertEqual('compute', sot.service.service_type) - self.assertTrue(sot.allow_create) - self.assertTrue(sot.allow_retrieve) - self.assertTrue(sot.allow_update) - self.assertTrue(sot.allow_delete) - self.assertTrue(sot.allow_list) - - def test_make_it(self): - sot = server_meta.ServerMeta(EXAMPLE) - self.assertEqual(EXAMPLE['key'], sot.key) - self.assertEqual(EXAMPLE['server_id'], sot.server_id) - self.assertEqual(EXAMPLE['value'], sot.value) - - def test_create(self): - resp = mock.Mock() - resp.body = FAKE_RESPONSE - resp.json = mock.Mock(return_value=resp.body) - sess = mock.Mock() - sess.put = mock.Mock(return_value=resp) - sot = server_meta.ServerMeta(EXAMPLE) - - sot.create(sess) - - url = 'servers/' + FAKE_SERVER_ID + '/metadata/' + FAKE_KEY - body = {"meta": {FAKE_KEY: FAKE_VALUE}} - sess.put.assert_called_with(url, endpoint_filter=sot.service, - json=body) - self.assertEqual(FAKE_VALUE, sot.value) - self.assertEqual(FAKE_KEY, sot.key) - self.assertEqual(FAKE_SERVER_ID, sot.server_id) - - def test_get(self): - resp = mock.Mock() - resp.body = FAKE_RESPONSES - resp.json = mock.Mock(return_value=resp.body) - sess = mock.Mock() - sess.get = mock.Mock(return_value=resp) - sot = server_meta.ServerMeta() - path_args = {'server_id': FAKE_SERVER_ID} - - resp = sot.list(sess, path_args=path_args) - - url = '/servers/' + FAKE_SERVER_ID + '/metadata' - sess.get.assert_called_with(url, endpoint_filter=sot.service, - params={}) - self.assertEqual(1, len(resp)) - self.assertEqual(FAKE_SERVER_ID, resp[0].server_id) - self.assertEqual(FAKE_KEY, resp[0].key) - self.assertEqual(FAKE_VALUE, resp[0].value) - - def test_update(self): - resp = mock.Mock() - resp.body = FAKE_RESPONSE - resp.json = mock.Mock(return_value=resp.body) - sess = mock.Mock() - sess.put = mock.Mock(return_value=resp) - sot = server_meta.ServerMeta(EXAMPLE) - - sot.update(sess) - - url = 'servers/' + FAKE_SERVER_ID + '/metadata/' + FAKE_KEY - body = {"meta": {FAKE_KEY: FAKE_VALUE}} - sess.put.assert_called_with(url, endpoint_filter=sot.service, - json=body) - self.assertEqual(FAKE_VALUE, sot.value) - self.assertEqual(FAKE_KEY, sot.key) - self.assertEqual(FAKE_SERVER_ID, sot.server_id) - - def test_delete(self): - resp = mock.Mock() - resp.body = FAKE_RESPONSES - resp.json = mock.Mock(return_value=resp.body) - sess = mock.Mock() - sess.delete = mock.Mock(return_value=resp) - sot = server_meta.ServerMeta(EXAMPLE) - - sot.delete(sess) - - url = 'servers/' + FAKE_SERVER_ID + '/metadata/' + FAKE_KEY - headers = {'Accept': ''} - sess.delete.assert_called_with(url, endpoint_filter=sot.service, - headers=headers) - - def test_list(self): - resp = mock.Mock() - resp.body = FAKE_RESPONSES - resp.json = mock.Mock(return_value=resp.body) - sess = mock.Mock() - sess.get = mock.Mock(return_value=resp) - sot = server_meta.ServerMeta() - path_args = {'server_id': FAKE_SERVER_ID} - - resp = sot.list(sess, path_args=path_args) - - url = '/servers/' + FAKE_SERVER_ID + '/metadata' - sess.get.assert_called_with(url, endpoint_filter=sot.service, - params={}) - self.assertEqual(1, len(resp)) - self.assertEqual(FAKE_SERVER_ID, resp[0].server_id) - self.assertEqual(FAKE_KEY, resp[0].key) - self.assertEqual(FAKE_VALUE, resp[0].value) diff --git a/openstack/tests/unit/compute/v2/test_server_metadata.py b/openstack/tests/unit/compute/v2/test_server_metadata.py deleted file mode 100644 index 8a1fc095..00000000 --- a/openstack/tests/unit/compute/v2/test_server_metadata.py +++ /dev/null @@ -1,97 +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.compute.v2 import server_metadata - -FAKE_SERVER_ID = 'cervidae' -FAKE_KEY = 'cervus' -FAKE_VALUE = 'canadensis' -FAKE_KEY2 = 'odocoileus' -FAKE_VALUE2 = 'hemionus' -EXAMPLE = { - 'server_id': FAKE_SERVER_ID, - FAKE_KEY: FAKE_VALUE, -} -FAKE_RESPONSE = {"metadata": {FAKE_KEY: FAKE_VALUE, FAKE_KEY2: FAKE_VALUE2}} - - -class TestServerMetadata(testtools.TestCase): - - def test_basic(self): - sot = server_metadata.ServerMetadata() - self.assertEqual('metadata', sot.resource_key) - self.assertIsNone(sot.resources_key) - self.assertEqual('/servers/%(server_id)s/metadata', sot.base_path) - self.assertEqual('compute', sot.service.service_type) - self.assertTrue(sot.allow_create) - self.assertTrue(sot.allow_retrieve) - self.assertTrue(sot.allow_update) - self.assertFalse(sot.allow_delete) - self.assertFalse(sot.allow_list) - - def test_make_it(self): - sot = server_metadata.ServerMetadata(EXAMPLE) - self.assertEqual(EXAMPLE['server_id'], sot.server_id) - self.assertEqual(FAKE_VALUE, sot[FAKE_KEY]) - - def test_create(self): - resp = mock.Mock() - resp.body = FAKE_RESPONSE - resp.json = mock.Mock(return_value=resp.body) - sess = mock.Mock() - sess.put = mock.Mock(return_value=resp) - sot = server_metadata.ServerMetadata(EXAMPLE.copy()) - - sot.create(sess) - - url = '/servers/' + FAKE_SERVER_ID + '/metadata' - body = {"metadata": {FAKE_KEY: FAKE_VALUE}} - sess.put.assert_called_with(url, endpoint_filter=sot.service, - json=body) - self.assertEqual(FAKE_SERVER_ID, sot.server_id) - self.assertEqual(FAKE_VALUE, sot[FAKE_KEY]) - - def test_get(self): - resp = mock.Mock() - resp.body = FAKE_RESPONSE - resp.json = mock.Mock(return_value=resp.body) - sess = mock.Mock() - sess.get = mock.Mock(return_value=resp) - sot = server_metadata.ServerMetadata(EXAMPLE.copy()) - - sot.get(sess) - - url = '/servers/' + FAKE_SERVER_ID + '/metadata' - sess.get.assert_called_with(url, endpoint_filter=sot.service) - self.assertEqual(FAKE_SERVER_ID, sot.server_id) - self.assertEqual(FAKE_VALUE, sot[FAKE_KEY]) - self.assertEqual(FAKE_VALUE2, sot[FAKE_KEY2]) - - def test_update(self): - resp = mock.Mock() - resp.body = FAKE_RESPONSE - resp.json = mock.Mock(return_value=resp.body) - sess = mock.Mock() - sess.put = mock.Mock(return_value=resp) - sot = server_metadata.ServerMetadata(EXAMPLE.copy()) - - sot.update(sess) - - url = '/servers/' + FAKE_SERVER_ID + '/metadata' - body = {"metadata": {FAKE_KEY: FAKE_VALUE}} - sess.put.assert_called_with(url, endpoint_filter=sot.service, - json=body) - self.assertEqual(FAKE_SERVER_ID, sot.server_id) - self.assertEqual(FAKE_VALUE, sot[FAKE_KEY]) diff --git a/openstack/tests/unit/test_proxy_base.py b/openstack/tests/unit/test_proxy_base.py index a39a225b..90d660e3 100644 --- a/openstack/tests/unit/test_proxy_base.py +++ b/openstack/tests/unit/test_proxy_base.py @@ -50,7 +50,7 @@ class TestProxyBase(base.TestCase): # the _verify method. It will be removed once there is one API to # be verifying. def _verify2(self, mock_method, test_method, - method_args=None, method_kwargs=None, + method_args=None, method_kwargs=None, method_result=None, expected_args=None, expected_kwargs=None, expected_result=None): with mock.patch(mock_method) as mocked: @@ -62,8 +62,12 @@ class TestProxyBase(base.TestCase): expected_args = expected_args or () expected_kwargs = expected_kwargs or {} - self.assertEqual(expected_result, test_method(*method_args, - **method_kwargs)) + if method_result: + self.assertEqual(method_result, test_method(*method_args, + **method_kwargs)) + else: + self.assertEqual(expected_result, test_method(*method_args, + **method_kwargs)) mocked.assert_called_with(*expected_args, **expected_kwargs) else: self.assertEqual(expected_result, test_method())