oslo.vmware/oslo_vmware/tests/test_rw_handles.py
Sean McGinnis c9c34169de
Use unittest.mock instead of third party mock
Now that we no longer support py27, we can use the standard library
unittest.mock module instead of the third party mock lib.

Change-Id: I4d8eada1df0ec43162d4729bf75147eb40252b72
Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
2020-03-31 14:37:19 -05:00

434 lines
16 KiB
Python

# Copyright (c) 2014 VMware, Inc.
# All Rights Reserved.
#
# 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.
"""Unit tests for read and write handles for image transfer."""
import ssl
from unittest import mock
import requests
from oslo_vmware import exceptions
from oslo_vmware import rw_handles
from oslo_vmware.tests import base
from oslo_vmware import vim_util
class FileHandleTest(base.TestCase):
"""Tests for FileHandle."""
def test_close(self):
file_handle = mock.Mock()
vmw_http_file = rw_handles.FileHandle(file_handle)
vmw_http_file.close()
file_handle.close.assert_called_once_with()
@mock.patch('urllib3.connection.HTTPConnection')
def test_create_connection_http(self, http_conn):
conn = mock.Mock()
http_conn.return_value = conn
handle = rw_handles.FileHandle(None)
ret = handle._create_connection('http://localhost/foo?q=bar', 'GET')
self.assertEqual(conn, ret)
conn.putrequest.assert_called_once_with('GET', '/foo?q=bar')
@mock.patch('urllib3.connection.HTTPSConnection')
def test_create_connection_https(self, https_conn):
conn = mock.Mock()
https_conn.return_value = conn
handle = rw_handles.FileHandle(None)
ret = handle._create_connection('https://localhost/foo?q=bar', 'GET')
self.assertEqual(conn, ret)
ca_store = requests.certs.where()
conn.set_cert.assert_called_once_with(
ca_certs=ca_store, cert_reqs=ssl.CERT_NONE,
assert_fingerprint=None)
conn.putrequest.assert_called_once_with('GET', '/foo?q=bar')
@mock.patch('urllib3.connection.HTTPSConnection')
def test_create_connection_https_with_cacerts(self, https_conn):
conn = mock.Mock()
https_conn.return_value = conn
handle = rw_handles.FileHandle(None)
ret = handle._create_connection('https://localhost/foo?q=bar', 'GET',
cacerts=True)
self.assertEqual(conn, ret)
ca_store = requests.certs.where()
conn.set_cert.assert_called_once_with(
ca_certs=ca_store, cert_reqs=ssl.CERT_REQUIRED,
assert_fingerprint=None)
@mock.patch('urllib3.connection.HTTPSConnection')
def test_create_connection_https_with_ssl_thumbprint(self, https_conn):
conn = mock.Mock()
https_conn.return_value = conn
handle = rw_handles.FileHandle(None)
cacerts = mock.sentinel.cacerts
thumbprint = mock.sentinel.thumbprint
ret = handle._create_connection('https://localhost/foo?q=bar', 'GET',
cacerts=cacerts,
ssl_thumbprint=thumbprint)
self.assertEqual(conn, ret)
conn.set_cert.assert_called_once_with(
ca_certs=cacerts, cert_reqs=None, assert_fingerprint=thumbprint)
class FileWriteHandleTest(base.TestCase):
"""Tests for FileWriteHandle."""
def setUp(self):
super(FileWriteHandleTest, self).setUp()
vim_cookie = mock.Mock()
vim_cookie.name = 'name'
vim_cookie.value = 'value'
self._conn = mock.Mock()
patcher = mock.patch(
'urllib3.connection.HTTPConnection')
self.addCleanup(patcher.stop)
HTTPConnectionMock = patcher.start()
HTTPConnectionMock.return_value = self._conn
self.vmw_http_write_file = rw_handles.FileWriteHandle(
'10.1.2.3', 443, 'dc-0', 'ds-0', [vim_cookie], '1.vmdk', 100,
'http')
def test_write(self):
self.vmw_http_write_file.write(None)
self._conn.send.assert_called_once_with(None)
def test_close(self):
self.vmw_http_write_file.close()
self._conn.getresponse.assert_called_once_with()
self._conn.close.assert_called_once_with()
class VmdkHandleTest(base.TestCase):
"""Tests for VmdkHandle."""
def test_find_vmdk_url(self):
device_url_0 = mock.Mock()
device_url_0.disk = False
device_url_1 = mock.Mock()
device_url_1.disk = True
device_url_1.url = 'https://*/ds1/vm1.vmdk'
device_url_1.sslThumbprint = '11:22:33:44:55'
lease_info = mock.Mock()
lease_info.deviceUrl = [device_url_0, device_url_1]
host = '10.1.2.3'
port = 443
exp_url = 'https://%s:%d/ds1/vm1.vmdk' % (host, port)
vmw_http_file = rw_handles.VmdkHandle(None, None, None, None)
url, thumbprint = vmw_http_file._find_vmdk_url(lease_info, host, port)
self.assertEqual(exp_url, url)
self.assertEqual('11:22:33:44:55', thumbprint)
def test_update_progress(self):
session = mock.Mock()
lease = mock.Mock()
handle = rw_handles.VmdkHandle(session, lease, 'fake-url', None)
handle._get_progress = mock.Mock(return_value=50)
handle.update_progress()
session.invoke_api.assert_called_once_with(session.vim,
'HttpNfcLeaseProgress',
lease, percent=50)
def test_update_progress_with_error(self):
session = mock.Mock()
handle = rw_handles.VmdkHandle(session, None, 'fake-url', None)
handle._get_progress = mock.Mock(return_value=0)
session.invoke_api.side_effect = exceptions.VimException(None)
self.assertRaises(exceptions.VimException, handle.update_progress)
def test_fileno(self):
session = mock.Mock()
handle = rw_handles.VmdkHandle(session, None, 'fake-url', None)
self.assertRaises(IOError, handle.fileno)
class VmdkWriteHandleTest(base.TestCase):
"""Tests for VmdkWriteHandle."""
def setUp(self):
super(VmdkWriteHandleTest, self).setUp()
self._conn = mock.Mock()
patcher = mock.patch(
'urllib3.connection.HTTPConnection')
self.addCleanup(patcher.stop)
HTTPConnectionMock = patcher.start()
HTTPConnectionMock.return_value = self._conn
def _create_mock_session(self, disk=True, progress=-1):
device_url = mock.Mock()
device_url.disk = disk
device_url.url = 'http://*/ds/disk1.vmdk'
lease_info = mock.Mock()
lease_info.deviceUrl = [device_url]
session = mock.Mock()
def session_invoke_api_side_effect(module, method, *args, **kwargs):
if module == session.vim:
if method == 'ImportVApp':
return mock.Mock()
elif method == 'HttpNfcLeaseProgress':
self.assertEqual(progress, kwargs['percent'])
return
return lease_info
session.invoke_api.side_effect = session_invoke_api_side_effect
vim_cookie = mock.Mock()
vim_cookie.name = 'name'
vim_cookie.value = 'value'
session.vim.client.options.transport.cookiejar = [vim_cookie]
return session
def test_init_failure(self):
session = self._create_mock_session(False)
self.assertRaises(exceptions.VimException,
rw_handles.VmdkWriteHandle,
session,
'10.1.2.3',
443,
'rp-1',
'folder-1',
None,
100)
def test_write(self):
session = self._create_mock_session()
handle = rw_handles.VmdkWriteHandle(session, '10.1.2.3', 443,
'rp-1', 'folder-1', None,
100)
data = [1] * 10
handle.write(data)
self.assertEqual(len(data), handle._bytes_written)
self._conn.putrequest.assert_called_once_with('PUT', '/ds/disk1.vmdk')
self._conn.send.assert_called_once_with(data)
def test_tell(self):
session = self._create_mock_session()
handle = rw_handles.VmdkWriteHandle(session, '10.1.2.3', 443,
'rp-1', 'folder-1', None,
100)
data = [1] * 10
handle.write(data)
self.assertEqual(len(data), handle._bytes_written)
self.assertEqual(len(data), handle.tell())
def test_write_post(self):
session = self._create_mock_session()
handle = rw_handles.VmdkWriteHandle(session, '10.1.2.3', 443,
'rp-1', 'folder-1', None,
100, http_method='POST')
data = [1] * 10
handle.write(data)
self.assertEqual(len(data), handle._bytes_written)
self._conn.putrequest.assert_called_once_with('POST', '/ds/disk1.vmdk')
self._conn.send.assert_called_once_with(data)
def test_update_progress(self):
vmdk_size = 100
data_size = 10
session = self._create_mock_session(True, 10)
handle = rw_handles.VmdkWriteHandle(session, '10.1.2.3', 443,
'rp-1', 'folder-1', None,
vmdk_size)
handle.write([1] * data_size)
handle.update_progress()
def test_close(self):
session = self._create_mock_session()
handle = rw_handles.VmdkWriteHandle(session, '10.1.2.3', 443,
'rp-1', 'folder-1', None,
100)
def session_invoke_api_side_effect(module, method, *args, **kwargs):
if module == vim_util and method == 'get_object_property':
return 'ready'
self.assertEqual(session.vim, module)
self.assertEqual('HttpNfcLeaseComplete', method)
session.invoke_api = mock.Mock(
side_effect=session_invoke_api_side_effect)
handle.close()
self.assertEqual(2, session.invoke_api.call_count)
class VmdkReadHandleTest(base.TestCase):
"""Tests for VmdkReadHandle."""
def setUp(self):
super(VmdkReadHandleTest, self).setUp()
def _mock_connection(self, read_data='fake-data'):
self._resp = mock.Mock()
self._resp.read.return_value = read_data
self._conn = mock.Mock()
self._conn.getresponse.return_value = self._resp
patcher = mock.patch(
'urllib3.connection.HTTPConnection')
self.addCleanup(patcher.stop)
HTTPConnectionMock = patcher.start()
HTTPConnectionMock.return_value = self._conn
def _create_mock_session(self, disk=True, progress=-1,
read_data='fake-data'):
self._mock_connection(read_data=read_data)
device_url = mock.Mock()
device_url.disk = disk
device_url.url = 'http://*/ds/disk1.vmdk'
lease_info = mock.Mock()
lease_info.deviceUrl = [device_url]
session = mock.Mock()
def session_invoke_api_side_effect(module, method, *args, **kwargs):
if module == session.vim:
if method == 'ExportVm':
return mock.Mock()
elif method == 'HttpNfcLeaseProgress':
self.assertEqual(progress, kwargs['percent'])
return
return lease_info
session.invoke_api.side_effect = session_invoke_api_side_effect
vim_cookie = mock.Mock()
vim_cookie.name = 'name'
vim_cookie.value = 'value'
session.vim.client.options.transport.cookiejar = [vim_cookie]
return session
def test_init_failure(self):
session = self._create_mock_session(False)
self.assertRaises(exceptions.VimException,
rw_handles.VmdkReadHandle,
session,
'10.1.2.3',
443,
'vm-1',
'[ds] disk1.vmdk',
100)
def test_read(self):
chunk_size = rw_handles.READ_CHUNKSIZE
session = self._create_mock_session()
handle = rw_handles.VmdkReadHandle(session, '10.1.2.3', 443,
'vm-1', '[ds] disk1.vmdk',
chunk_size * 10)
fake_data = 'fake-data'
data = handle.read(chunk_size)
self.assertEqual(fake_data, data)
self.assertEqual(len(fake_data), handle._bytes_read)
def test_read_small(self):
read_data = 'fake'
session = self._create_mock_session(read_data=read_data)
read_size = len(read_data)
handle = rw_handles.VmdkReadHandle(session, '10.1.2.3', 443,
'vm-1', '[ds] disk1.vmdk',
read_size * 10)
handle.read(read_size)
self.assertEqual(read_size, handle._bytes_read)
def test_tell(self):
chunk_size = rw_handles.READ_CHUNKSIZE
session = self._create_mock_session()
handle = rw_handles.VmdkReadHandle(session, '10.1.2.3', 443,
'vm-1', '[ds] disk1.vmdk',
chunk_size * 10)
data = handle.read(chunk_size)
self.assertEqual(len(data), handle.tell())
def test_update_progress(self):
chunk_size = len('fake-data')
vmdk_size = chunk_size * 10
session = self._create_mock_session(True, 10)
handle = rw_handles.VmdkReadHandle(session, '10.1.2.3', 443,
'vm-1', '[ds] disk1.vmdk',
vmdk_size)
data = handle.read(chunk_size)
handle.update_progress()
self.assertEqual('fake-data', data)
def test_close(self):
session = self._create_mock_session()
handle = rw_handles.VmdkReadHandle(session, '10.1.2.3', 443,
'vm-1', '[ds] disk1.vmdk',
100)
def session_invoke_api_side_effect(module, method, *args, **kwargs):
if module == vim_util and method == 'get_object_property':
return 'ready'
self.assertEqual(session.vim, module)
self.assertEqual('HttpNfcLeaseComplete', method)
session.invoke_api = mock.Mock(
side_effect=session_invoke_api_side_effect)
handle.close()
self.assertEqual(2, session.invoke_api.call_count)
def test_close_with_error(self):
session = self._create_mock_session()
handle = rw_handles.VmdkReadHandle(session, '10.1.2.3', 443,
'vm-1', '[ds] disk1.vmdk',
100)
session.invoke_api.side_effect = exceptions.VimException(None)
self.assertRaises(exceptions.VimException, handle.close)
self._resp.close.assert_called_once_with()
class ImageReadHandleTest(base.TestCase):
"""Tests for ImageReadHandle."""
def test_read(self):
max_items = 10
item = [1] * 10
class ImageReadIterator(object):
def __init__(self):
self.num_items = 0
def __iter__(self):
return self
def __next__(self):
if (self.num_items < max_items):
self.num_items += 1
return item
raise StopIteration
next = __next__
handle = rw_handles.ImageReadHandle(ImageReadIterator())
for _ in range(0, max_items):
self.assertEqual(item, handle.read(10))
self.assertFalse(handle.read(10))