From e95d8e9abfc4822e34dfbaeaf762ea3def4aa0f5 Mon Sep 17 00:00:00 2001
From: Monty Taylor <mordred@inaugust.com>
Date: Sun, 24 Jun 2018 11:32:47 -0500
Subject: [PATCH] Finish migrating image tests to requests-mock

We let some of these slip through originally. Fix them so we can do
other things.

Guess what? There were bugs in the v1 codepath.

Change-Id: Ia51598548cde0ddb4f9e96b166274e9a104cf649
---
 shade/openstackcloud.py        |  17 +-
 shade/tests/unit/test_image.py | 471 +++++++++++++++++----------------
 2 files changed, 249 insertions(+), 239 deletions(-)

diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py
index ac1290cea..59fcd50cf 100644
--- a/shade/openstackcloud.py
+++ b/shade/openstackcloud.py
@@ -4867,7 +4867,9 @@ class OpenStackCloud(
         image_kwargs['properties'].update(meta)
         image_kwargs['name'] = name
 
-        image = self._image_client.post('/images', json=image_kwargs)
+        image = self._get_and_munchify(
+            'image',
+            self._image_client.post('/images', json=image_kwargs))
         checksum = image_kwargs['properties'].get(IMAGE_MD5_KEY, '')
 
         try:
@@ -4879,21 +4881,24 @@ class OpenStackCloud(
             if checksum:
                 headers['x-image-meta-checksum'] = checksum
 
-            image = self._image_client.put(
-                '/images/{id}'.format(id=image.id),
-                headers=headers, data=image_data)
+            image = self._get_and_munchify(
+                'image',
+                self._image_client.put(
+                    '/images/{id}'.format(id=image.id),
+                    headers=headers, data=image_data))
 
         except exc.OpenStackCloudHTTPError:
             self.log.debug("Deleting failed upload of image %s", name)
             try:
-                self._image_client.delete('/images/{id}'.format(id=image.id))
+                self._image_client.delete(
+                    '/images/{id}'.format(id=image.id))
             except exc.OpenStackCloudHTTPError:
                 # We're just trying to clean up - if it doesn't work - shrug
                 self.log.debug(
                     "Failed deleting image after we failed uploading it.",
                     exc_info=True)
             raise
-        return image
+        return self._normalize_image(image)
 
     def _upload_image_put(
             self, name, filename, meta, wait, timeout, **image_kwargs):
diff --git a/shade/tests/unit/test_image.py b/shade/tests/unit/test_image.py
index b9ec47937..dae58a56f 100644
--- a/shade/tests/unit/test_image.py
+++ b/shade/tests/unit/test_image.py
@@ -19,8 +19,6 @@ import operator
 import tempfile
 import uuid
 
-import mock
-import munch
 import six
 
 import shade
@@ -484,295 +482,302 @@ class TestImage(BaseTestImage):
             name, imagefile.name, wait=True, timeout=1,
             is_public=False, **kwargs)
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_create_image_put_v1(
-            self, mock_image_client, mock_is_client_version):
-        # TODO(mordred) Fix this to use requests_mock
-        mock_is_client_version.return_value = False
-        mock_image_client.get.return_value = []
-        self.assertEqual([], self.cloud.list_images())
+    def test_create_image_put_v1(self):
+        self.cloud.cloud_config.config['image_api_version'] = '1'
 
-        args = {'name': '42 name',
+        args = {'name': self.image_name,
                 'container_format': 'bare', 'disk_format': 'qcow2',
                 'properties': {
-                    'owner_specified.shade.md5': mock.ANY,
-                    'owner_specified.shade.sha256': mock.ANY,
-                    'owner_specified.shade.object': 'images/42 name',
+                    'owner_specified.shade.md5': fakes.NO_MD5,
+                    'owner_specified.shade.sha256': fakes.NO_SHA256,
+                    'owner_specified.shade.object': 'images/{name}'.format(
+                        name=self.image_name),
                     'is_public': False}}
-        ret = munch.Munch(args.copy())
-        ret['id'] = '42'
+
+        ret = args.copy()
+        ret['id'] = self.image_id
         ret['status'] = 'success'
-        mock_image_client.get.side_effect = [
-            [],
-            [ret],
-            [ret],
-        ]
-        mock_image_client.post.return_value = ret
-        mock_image_client.put.return_value = ret
-        self._call_create_image('42 name')
-        mock_image_client.post.assert_called_with('/images', json=args)
-        mock_image_client.put.assert_called_with(
-            '/images/42', data=mock.ANY,
-            headers={
-                'x-image-meta-checksum': mock.ANY,
-                'x-glance-registry-purge-props': 'false'
-            })
-        mock_image_client.get.assert_called_with('/images/detail', params={})
-        self.assertEqual(
-            self._munch_images(ret), self.cloud.list_images())
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_create_image_put_v1_bad_delete(
-            self, mock_image_client, mock_is_client_version):
-        mock_is_client_version.return_value = False
-        mock_image_client.get.return_value = []
-        self.assertEqual([], self.cloud.list_images())
+        self.register_uris([
+            dict(method='GET',
+                 uri='https://image.example.com/v1/images/detail',
+                 json={'images': []}),
+            dict(method='POST',
+                 uri='https://image.example.com/v1/images',
+                 json={'image': ret},
+                 validate=dict(json=args)),
+            dict(method='PUT',
+                 uri='https://image.example.com/v1/images/{id}'.format(
+                     id=self.image_id),
+                 json={'image': ret},
+                 validate=dict(headers={
+                     'x-image-meta-checksum': fakes.NO_MD5,
+                     'x-glance-registry-purge-props': 'false'
+                 })),
+            dict(method='GET',
+                 uri='https://image.example.com/v1/images/detail',
+                 json={'images': [ret]}),
+        ])
+        self._call_create_image(self.image_name)
+        self.assertEqual(self._munch_images(ret), self.cloud.list_images())
 
-        args = {'name': '42 name',
+    def test_create_image_put_v1_bad_delete(self):
+        self.cloud.cloud_config.config['image_api_version'] = '1'
+
+        args = {'name': self.image_name,
                 'container_format': 'bare', 'disk_format': 'qcow2',
                 'properties': {
-                    'owner_specified.shade.md5': mock.ANY,
-                    'owner_specified.shade.sha256': mock.ANY,
-                    'owner_specified.shade.object': 'images/42 name',
+                    'owner_specified.shade.md5': fakes.NO_MD5,
+                    'owner_specified.shade.sha256': fakes.NO_SHA256,
+                    'owner_specified.shade.object': 'images/{name}'.format(
+                        name=self.image_name),
                     'is_public': False}}
-        ret = munch.Munch(args.copy())
-        ret['id'] = '42'
+
+        ret = args.copy()
+        ret['id'] = self.image_id
         ret['status'] = 'success'
-        mock_image_client.get.side_effect = [
-            [],
-            [ret],
-        ]
-        mock_image_client.post.return_value = ret
-        mock_image_client.put.side_effect = exc.OpenStackCloudHTTPError(
-            "Some error", {})
+
+        self.register_uris([
+            dict(method='GET',
+                 uri='https://image.example.com/v1/images/detail',
+                 json={'images': []}),
+            dict(method='POST',
+                 uri='https://image.example.com/v1/images',
+                 json={'image': ret},
+                 validate=dict(json=args)),
+            dict(method='PUT',
+                 uri='https://image.example.com/v1/images/{id}'.format(
+                     id=self.image_id),
+                 status_code=400,
+                 validate=dict(headers={
+                     'x-image-meta-checksum': fakes.NO_MD5,
+                     'x-glance-registry-purge-props': 'false'
+                 })),
+            dict(method='DELETE',
+                 uri='https://image.example.com/v1/images/{id}'.format(
+                     id=self.image_id),
+                 json={'images': [ret]}),
+        ])
+
         self.assertRaises(
             exc.OpenStackCloudHTTPError,
             self._call_create_image,
-            '42 name')
-        mock_image_client.post.assert_called_with('/images', json=args)
-        mock_image_client.put.assert_called_with(
-            '/images/42', data=mock.ANY,
-            headers={
-                'x-image-meta-checksum': mock.ANY,
-                'x-glance-registry-purge-props': 'false'
-            })
-        mock_image_client.delete.assert_called_with('/images/42')
+            self.image_name)
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_update_image_no_patch(
-            self, mock_image_client, mock_is_client_version):
-        mock_is_client_version.return_value = True
+        self.assert_calls()
+
+    def test_update_image_no_patch(self):
         self.cloud.image_api_use_tasks = False
 
-        mock_image_client.get.return_value = []
-        self.assertEqual([], self.cloud.list_images())
-
-        args = {'name': '42 name',
+        args = {'name': self.image_name,
                 'container_format': 'bare', 'disk_format': 'qcow2',
-                'owner_specified.shade.md5': mock.ANY,
-                'owner_specified.shade.sha256': mock.ANY,
-                'owner_specified.shade.object': 'images/42 name',
-                'visibility': 'private',
-                'min_disk': 0, 'min_ram': 0}
-        ret = munch.Munch(args.copy())
-        ret['id'] = '42'
+                'owner_specified.shade.md5': fakes.NO_MD5,
+                'owner_specified.shade.sha256': fakes.NO_SHA256,
+                'owner_specified.shade.object': 'images/{name}'.format(
+                    name=self.image_name),
+                'visibility': 'private'}
+
+        ret = args.copy()
+        ret['id'] = self.image_id
         ret['status'] = 'success'
-        mock_image_client.get.side_effect = [
-            [],
-            [ret],
-            [ret],
-        ]
+
         self.cloud.update_image_properties(
             image=self._image_dict(ret),
-            **{'owner_specified.shade.object': 'images/42 name'})
-        mock_image_client.get.assert_called_with('/images', params={})
-        mock_image_client.patch.assert_not_called()
+            **{'owner_specified.shade.object': 'images/{name}'.format(
+                name=self.image_name)})
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_create_image_put_v2_bad_delete(
-            self, mock_image_client, mock_is_client_version):
-        mock_is_client_version.return_value = True
+        self.assert_calls()
+
+    def test_create_image_put_v2_bad_delete(self):
         self.cloud.image_api_use_tasks = False
 
-        mock_image_client.get.return_value = []
-        self.assertEqual([], self.cloud.list_images())
-
-        args = {'name': '42 name',
+        args = {'name': self.image_name,
                 'container_format': 'bare', 'disk_format': 'qcow2',
-                'owner_specified.shade.md5': mock.ANY,
-                'owner_specified.shade.sha256': mock.ANY,
-                'owner_specified.shade.object': 'images/42 name',
-                'visibility': 'private',
-                'min_disk': 0, 'min_ram': 0}
-        ret = munch.Munch(args.copy())
-        ret['id'] = '42'
+                'owner_specified.shade.md5': fakes.NO_MD5,
+                'owner_specified.shade.sha256': fakes.NO_SHA256,
+                'owner_specified.shade.object': 'images/{name}'.format(
+                    name=self.image_name),
+                'visibility': 'private'}
+
+        ret = args.copy()
+        ret['id'] = self.image_id
         ret['status'] = 'success'
-        mock_image_client.get.side_effect = [
-            [],
-            [ret],
-            [ret],
-        ]
-        mock_image_client.post.return_value = ret
-        mock_image_client.put.side_effect = exc.OpenStackCloudHTTPError(
-            "Some error", {})
+
+        self.register_uris([
+            dict(method='GET',
+                 uri='https://image.example.com/v2/images',
+                 json={'images': []}),
+            dict(method='POST',
+                 uri='https://image.example.com/v2/images',
+                 json=ret,
+                 validate=dict(json=args)),
+            dict(method='PUT',
+                 uri='https://image.example.com/v2/images/{id}/file'.format(
+                     id=self.image_id),
+                 status_code=400,
+                 validate=dict(
+                     headers={
+                         'Content-Type': 'application/octet-stream',
+                     },
+                 )),
+            dict(method='DELETE',
+                 uri='https://image.example.com/v2/images/{id}'.format(
+                     id=self.image_id)),
+        ])
+
         self.assertRaises(
             exc.OpenStackCloudHTTPError,
             self._call_create_image,
-            '42 name', min_disk='0', min_ram=0)
-        mock_image_client.post.assert_called_with('/images', json=args)
-        mock_image_client.put.assert_called_with(
-            '/images/42/file',
-            headers={'Content-Type': 'application/octet-stream'},
-            data=mock.ANY)
-        mock_image_client.delete.assert_called_with('/images/42')
+            self.image_name)
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_create_image_put_bad_int(
-            self, mock_image_client, mock_is_client_version):
-        mock_is_client_version.return_value = True
+        self.assert_calls()
+
+    def test_create_image_put_bad_int(self):
         self.cloud.image_api_use_tasks = False
 
+        self.register_uris([
+            dict(method='GET',
+                 uri='https://image.example.com/v2/images',
+                 json={'images': []}),
+        ])
+
         self.assertRaises(
             exc.OpenStackCloudException,
-            self._call_create_image, '42 name', min_disk='fish', min_ram=0)
-        mock_image_client.post.assert_not_called()
+            self._call_create_image, self.image_name,
+            min_disk='fish', min_ram=0)
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_create_image_put_user_int(
-            self, mock_image_client, mock_is_client_version):
-        mock_is_client_version.return_value = True
+        self.assert_calls()
+
+    def test_create_image_put_user_int(self):
         self.cloud.image_api_use_tasks = False
 
-        args = {'name': '42 name',
+        args = {'name': self.image_name,
                 'container_format': 'bare', 'disk_format': u'qcow2',
-                'owner_specified.shade.md5': mock.ANY,
-                'owner_specified.shade.sha256': mock.ANY,
-                'owner_specified.shade.object': 'images/42 name',
+                'owner_specified.shade.md5': fakes.NO_MD5,
+                'owner_specified.shade.sha256': fakes.NO_SHA256,
+                'owner_specified.shade.object': 'images/{name}'.format(
+                    name=self.image_name),
                 'int_v': '12345',
                 'visibility': 'private',
                 'min_disk': 0, 'min_ram': 0}
-        ret = munch.Munch(args.copy())
-        ret['id'] = '42'
-        ret['status'] = 'success'
-        mock_image_client.get.side_effect = [
-            [],
-            [ret],
-            [ret]
-        ]
-        mock_image_client.post.return_value = ret
-        self._call_create_image(
-            '42 name', min_disk='0', min_ram=0, int_v=12345)
-        mock_image_client.post.assert_called_with('/images', json=args)
-        mock_image_client.put.assert_called_with(
-            '/images/42/file',
-            headers={'Content-Type': 'application/octet-stream'},
-            data=mock.ANY)
-        mock_image_client.get.assert_called_with('/images', params={})
-        self.assertEqual(
-            self._munch_images(ret), self.cloud.list_images())
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_create_image_put_meta_int(
-            self, mock_image_client, mock_is_client_version):
-        mock_is_client_version.return_value = True
+        ret = args.copy()
+        ret['id'] = self.image_id
+        ret['status'] = 'success'
+
+        self.register_uris([
+            dict(method='GET',
+                 uri='https://image.example.com/v2/images',
+                 json={'images': []}),
+            dict(method='POST',
+                 uri='https://image.example.com/v2/images',
+                 json=ret,
+                 validate=dict(json=args)),
+            dict(method='PUT',
+                 uri='https://image.example.com/v2/images/{id}/file'.format(
+                     id=self.image_id),
+                 validate=dict(
+                     headers={
+                         'Content-Type': 'application/octet-stream',
+                     },
+                 )),
+            dict(method='GET',
+                 uri='https://image.example.com/v2/images',
+                 json={'images': [ret]}),
+        ])
+
+        self._call_create_image(
+            self.image_name, min_disk='0', min_ram=0, int_v=12345)
+
+        self.assert_calls()
+
+    def test_create_image_put_meta_int(self):
         self.cloud.image_api_use_tasks = False
 
-        mock_image_client.get.return_value = []
-        self.assertEqual([], self.cloud.list_images())
-
-        self._call_create_image(
-            '42 name', min_disk='0', min_ram=0, meta={'int_v': 12345})
-        args = {'name': '42 name',
+        args = {'name': self.image_name,
                 'container_format': 'bare', 'disk_format': u'qcow2',
-                'owner_specified.shade.md5': mock.ANY,
-                'owner_specified.shade.sha256': mock.ANY,
-                'owner_specified.shade.object': 'images/42 name',
+                'owner_specified.shade.md5': fakes.NO_MD5,
+                'owner_specified.shade.sha256': fakes.NO_SHA256,
+                'owner_specified.shade.object': 'images/{name}'.format(
+                    name=self.image_name),
                 'int_v': 12345,
                 'visibility': 'private',
                 'min_disk': 0, 'min_ram': 0}
-        ret = munch.Munch(args.copy())
-        ret['id'] = '42'
-        ret['status'] = 'success'
-        mock_image_client.get.return_value = [ret]
-        mock_image_client.post.return_value = ret
-        mock_image_client.get.assert_called_with('/images', params={})
-        self.assertEqual(
-            self._munch_images(ret), self.cloud.list_images())
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_create_image_put_protected(
-            self, mock_image_client, mock_is_client_version):
-        mock_is_client_version.return_value = True
+        ret = args.copy()
+        ret['id'] = self.image_id
+        ret['status'] = 'success'
+
+        self.register_uris([
+            dict(method='GET',
+                 uri='https://image.example.com/v2/images',
+                 json={'images': []}),
+            dict(method='POST',
+                 uri='https://image.example.com/v2/images',
+                 json=ret,
+                 validate=dict(json=args)),
+            dict(method='PUT',
+                 uri='https://image.example.com/v2/images/{id}/file'.format(
+                     id=self.image_id),
+                 validate=dict(
+                     headers={
+                         'Content-Type': 'application/octet-stream',
+                     },
+                 )),
+            dict(method='GET',
+                 uri='https://image.example.com/v2/images',
+                 json={'images': [ret]}),
+        ])
+
+        self._call_create_image(
+            self.image_name, min_disk='0', min_ram=0, meta={'int_v': 12345})
+
+        self.assert_calls()
+
+    def test_create_image_put_protected(self):
         self.cloud.image_api_use_tasks = False
 
-        mock_image_client.get.return_value = []
-        self.assertEqual([], self.cloud.list_images())
-
-        args = {'name': '42 name',
+        args = {'name': self.image_name,
                 'container_format': 'bare', 'disk_format': u'qcow2',
-                'owner_specified.shade.md5': mock.ANY,
-                'owner_specified.shade.sha256': mock.ANY,
-                'owner_specified.shade.object': 'images/42 name',
+                'owner_specified.shade.md5': fakes.NO_MD5,
+                'owner_specified.shade.sha256': fakes.NO_SHA256,
+                'owner_specified.shade.object': 'images/{name}'.format(
+                    name=self.image_name),
+                'int_v': '12345',
                 'protected': False,
-                'int_v': '12345',
                 'visibility': 'private',
                 'min_disk': 0, 'min_ram': 0}
-        ret = munch.Munch(args.copy())
-        ret['id'] = '42'
+
+        ret = args.copy()
+        ret['id'] = self.image_id
         ret['status'] = 'success'
-        mock_image_client.get.side_effect = [
-            [],
-            [ret],
-            [ret],
-        ]
-        mock_image_client.put.return_value = ret
-        mock_image_client.post.return_value = ret
+
+        self.register_uris([
+            dict(method='GET',
+                 uri='https://image.example.com/v2/images',
+                 json={'images': []}),
+            dict(method='POST',
+                 uri='https://image.example.com/v2/images',
+                 json=ret,
+                 validate=dict(json=args)),
+            dict(method='PUT',
+                 uri='https://image.example.com/v2/images/{id}/file'.format(
+                     id=self.image_id),
+                 validate=dict(
+                     headers={
+                         'Content-Type': 'application/octet-stream',
+                     },
+                 )),
+            dict(method='GET',
+                 uri='https://image.example.com/v2/images',
+                 json={'images': [ret]}),
+        ])
+
         self._call_create_image(
-            '42 name', min_disk='0', min_ram=0, properties={'int_v': 12345},
-            protected=False)
-        mock_image_client.post.assert_called_with('/images', json=args)
-        mock_image_client.put.assert_called_with(
-            '/images/42/file', data=mock.ANY,
-            headers={'Content-Type': 'application/octet-stream'})
-        self.assertEqual(self._munch_images(ret), self.cloud.list_images())
+            self.image_name, min_disk='0', min_ram=0,
+            properties={'int_v': 12345}, protected=False)
 
-    @mock.patch.object(shade.OpenStackCloud, '_is_client_version')
-    @mock.patch.object(shade.OpenStackCloud, '_image_client')
-    def test_create_image_put_user_prop(
-            self, mock_image_client, mock_is_client_version):
-        mock_is_client_version.return_value = True
-        self.cloud.image_api_use_tasks = False
-
-        mock_image_client.get.return_value = []
-        self.assertEqual([], self.cloud.list_images())
-
-        args = {'name': '42 name',
-                'container_format': 'bare', 'disk_format': u'qcow2',
-                'owner_specified.shade.md5': mock.ANY,
-                'owner_specified.shade.sha256': mock.ANY,
-                'owner_specified.shade.object': 'images/42 name',
-                'int_v': '12345',
-                'xenapi_use_agent': 'False',
-                'visibility': 'private',
-                'min_disk': 0, 'min_ram': 0}
-        ret = munch.Munch(args.copy())
-        ret['id'] = '42'
-        ret['status'] = 'success'
-        mock_image_client.get.return_value = [ret]
-        mock_image_client.post.return_value = ret
-        self._call_create_image(
-            '42 name', min_disk='0', min_ram=0, properties={'int_v': 12345})
-        mock_image_client.get.assert_called_with('/images', params={})
-        self.assertEqual(
-            self._munch_images(ret), self.cloud.list_images())
+        self.assert_calls()
 
     def test_get_image_by_id(self):
         self.register_uris([