1
# Copyright (c) 2014 VMware, Inc.
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
17
Unit tests for functions and classes for image transfer.
22
from eventlet import greenthread
23
from eventlet import timeout
26
from oslo_vmware import exceptions
27
from oslo_vmware import image_transfer
28
from oslo_vmware import rw_handles
29
from oslo_vmware.tests import base
32
class BlockingQueueTest(base.TestCase):
33
"""Tests for BlockingQueue."""
38
max_transfer_size = 30
39
queue = image_transfer.BlockingQueue(max_size, max_transfer_size)
41
def get_side_effect():
42
return [1] * chunk_size
44
queue.get = mock.Mock(side_effect=get_side_effect)
46
data_item = queue.read(chunk_size)
50
self.assertEqual(max_transfer_size, queue._transferred)
51
exp_calls = [mock.call()] * int(math.ceil(float(max_transfer_size) /
53
self.assertEqual(exp_calls, queue.get.call_args_list)
56
queue = image_transfer.BlockingQueue(10, 30)
57
queue.put = mock.Mock()
59
for _ in range(0, write_count):
61
exp_calls = [mock.call([1])] * write_count
62
self.assertEqual(exp_calls, queue.put.call_args_list)
65
queue = image_transfer.BlockingQueue(10, 30)
66
self.assertRaises(IOError, queue.seek, 5)
69
queue = image_transfer.BlockingQueue(10, 30)
70
self.assertEqual(0, queue.tell())
71
queue.get = mock.Mock(return_value=[1] * 10)
73
self.assertEqual(10, queue.tell())
76
class ImageWriterTest(base.TestCase):
77
"""Tests for ImageWriter class."""
79
def _create_image_writer(self):
80
self.image_service = mock.Mock()
81
self.context = mock.Mock()
82
self.input_file = mock.Mock()
83
self.image_id = mock.Mock()
84
return image_transfer.ImageWriter(self.context, self.input_file,
85
self.image_service, self.image_id)
87
@mock.patch.object(greenthread, 'sleep')
88
def test_start(self, mock_sleep):
89
writer = self._create_image_writer()
90
status_list = ['queued', 'saving', 'active']
92
def image_service_show_side_effect(context, image_id):
93
status = status_list.pop(0)
94
return {'status': status}
96
self.image_service.show.side_effect = image_service_show_side_effect
97
exp_calls = [mock.call(self.context, self.image_id)] * len(status_list)
99
self.assertTrue(writer.wait())
100
self.image_service.update.assert_called_once_with(self.context,
102
data=self.input_file)
103
self.assertEqual(exp_calls, self.image_service.show.call_args_list)
105
def test_start_with_killed_status(self):
106
writer = self._create_image_writer()
108
def image_service_show_side_effect(_context, _image_id):
109
return {'status': 'killed'}
111
self.image_service.show.side_effect = image_service_show_side_effect
113
self.assertRaises(exceptions.ImageTransferException,
115
self.image_service.update.assert_called_once_with(self.context,
117
data=self.input_file)
118
self.image_service.show.assert_called_once_with(self.context,
121
def test_start_with_unknown_status(self):
122
writer = self._create_image_writer()
124
def image_service_show_side_effect(_context, _image_id):
125
return {'status': 'unknown'}
127
self.image_service.show.side_effect = image_service_show_side_effect
129
self.assertRaises(exceptions.ImageTransferException,
131
self.image_service.update.assert_called_once_with(self.context,
133
data=self.input_file)
134
self.image_service.show.assert_called_once_with(self.context,
137
def test_start_with_image_service_show_exception(self):
138
writer = self._create_image_writer()
139
self.image_service.show.side_effect = RuntimeError()
141
self.assertRaises(exceptions.ImageTransferException, writer.wait)
142
self.image_service.update.assert_called_once_with(self.context,
144
data=self.input_file)
145
self.image_service.show.assert_called_once_with(self.context,
149
class FileReadWriteTaskTest(base.TestCase):
150
"""Tests for FileReadWriteTask class."""
152
def test_start(self):
153
data_items = [[1] * 10, [1] * 20, [1] * 5, []]
155
def input_file_read_side_effect(arg):
156
self.assertEqual(arg, rw_handles.READ_CHUNKSIZE)
157
data = data_items[input_file_read_side_effect.i]
158
input_file_read_side_effect.i += 1
161
input_file_read_side_effect.i = 0
162
input_file = mock.Mock()
163
input_file.read.side_effect = input_file_read_side_effect
164
output_file = mock.Mock()
165
rw_task = image_transfer.FileReadWriteTask(input_file, output_file)
167
self.assertTrue(rw_task.wait())
168
self.assertEqual(len(data_items), input_file.read.call_count)
171
for i in range(0, len(data_items)):
172
exp_calls.append(mock.call(data_items[i]))
173
self.assertEqual(exp_calls, output_file.write.call_args_list)
175
self.assertEqual(len(data_items),
176
input_file.update_progress.call_count)
177
self.assertEqual(len(data_items),
178
output_file.update_progress.call_count)
180
def test_start_with_read_exception(self):
181
input_file = mock.Mock()
182
input_file.read.side_effect = RuntimeError()
183
output_file = mock.Mock()
184
rw_task = image_transfer.FileReadWriteTask(input_file, output_file)
186
self.assertRaises(exceptions.ImageTransferException, rw_task.wait)
187
input_file.read.assert_called_once_with(rw_handles.READ_CHUNKSIZE)
190
class ImageTransferUtilityTest(base.TestCase):
191
"""Tests for image_transfer utility methods."""
193
@mock.patch.object(timeout, 'Timeout')
194
@mock.patch.object(image_transfer, 'ImageWriter')
195
@mock.patch.object(image_transfer, 'FileReadWriteTask')
196
@mock.patch.object(image_transfer, 'BlockingQueue')
197
def test_start_transfer(self, fake_BlockingQueue, fake_FileReadWriteTask,
198
fake_ImageWriter, fake_Timeout):
200
context = mock.Mock()
201
read_file_handle = mock.Mock()
202
read_file_handle.close = mock.Mock()
203
image_service = mock.Mock()
204
image_id = mock.Mock()
205
blocking_queue = mock.Mock()
207
write_file_handle1 = mock.Mock()
208
write_file_handle1.close = mock.Mock()
209
write_file_handle2 = None
210
write_file_handles = [write_file_handle1, write_file_handle2]
213
blocking_queue_size = 10
217
fake_BlockingQueue.return_value = blocking_queue
218
fake_timer = mock.Mock()
219
fake_timer.cancel = mock.Mock()
220
fake_Timeout.return_value = fake_timer
222
for write_file_handle in write_file_handles:
223
image_transfer._start_transfer(context,
227
write_file_handle=write_file_handle,
228
image_service=image_service,
230
image_meta=image_meta)
232
exp_calls = [mock.call(blocking_queue_size,
233
max_data_size)] * len(write_file_handles)
234
self.assertEqual(exp_calls,
235
fake_BlockingQueue.call_args_list)
237
exp_calls2 = [mock.call(read_file_handle, blocking_queue),
238
mock.call(blocking_queue, write_file_handle1),
239
mock.call(read_file_handle, blocking_queue)]
240
self.assertEqual(exp_calls2,
241
fake_FileReadWriteTask.call_args_list)
243
exp_calls3 = mock.call(context, blocking_queue, image_service,
244
image_id, image_meta)
245
self.assertEqual(exp_calls3,
246
fake_ImageWriter.call_args)
248
exp_calls4 = [mock.call(timeout_secs)] * len(write_file_handles)
249
self.assertEqual(exp_calls4,
250
fake_Timeout.call_args_list)
252
self.assertEqual(len(write_file_handles),
253
fake_timer.cancel.call_count)
255
self.assertEqual(len(write_file_handles),
256
read_file_handle.close.call_count)
258
write_file_handle1.close.assert_called_once()
260
@mock.patch.object(image_transfer, 'FileReadWriteTask')
261
@mock.patch.object(image_transfer, 'BlockingQueue')
262
def test_start_transfer_with_no_image_destination(self, fake_BlockingQueue,
263
fake_FileReadWriteTask):
265
context = mock.Mock()
266
read_file_handle = mock.Mock()
267
write_file_handle = None
272
blocking_queue_size = 10
274
blocking_queue = mock.Mock()
276
fake_BlockingQueue.return_value = blocking_queue
278
self.assertRaises(ValueError,
279
image_transfer._start_transfer,
284
write_file_handle=write_file_handle,
285
image_service=image_service,
287
image_meta=image_meta)
289
fake_BlockingQueue.assert_called_once_with(blocking_queue_size,
292
fake_FileReadWriteTask.assert_called_once_with(read_file_handle,
295
@mock.patch('oslo_vmware.rw_handles.FileWriteHandle')
296
@mock.patch('oslo_vmware.rw_handles.ImageReadHandle')
297
@mock.patch.object(image_transfer, '_start_transfer')
298
def test_download_flat_image(
301
fake_rw_handles_ImageReadHandle,
302
fake_rw_handles_FileWriteHandle):
304
context = mock.Mock()
305
image_id = mock.Mock()
306
image_service = mock.Mock()
307
image_service.download = mock.Mock()
308
image_service.download.return_value = 'fake_iter'
310
fake_ImageReadHandle = 'fake_ImageReadHandle'
311
fake_FileWriteHandle = 'fake_FileWriteHandle'
319
file_path = '/fake_path'
321
fake_rw_handles_ImageReadHandle.return_value = fake_ImageReadHandle
322
fake_rw_handles_FileWriteHandle.return_value = fake_FileWriteHandle
324
image_transfer.download_flat_image(
329
image_size=image_size,
332
data_center_name=dc_path,
333
datastore_name=ds_name,
337
image_service.download.assert_called_once_with(context, image_id)
339
fake_rw_handles_ImageReadHandle.assert_called_once_with('fake_iter')
341
fake_rw_handles_FileWriteHandle.assert_called_once_with(
351
fake_transfer.assert_called_once_with(
354
fake_ImageReadHandle,
356
write_file_handle=fake_FileWriteHandle)
358
@mock.patch('oslo_vmware.rw_handles.VmdkWriteHandle')
359
@mock.patch.object(image_transfer, '_start_transfer')
360
def test_download_stream_optimized_data(self, fake_transfer,
361
fake_rw_handles_VmdkWriteHandle):
363
context = mock.Mock()
364
session = mock.Mock()
365
read_handle = mock.Mock()
370
resource_pool = 'rp-1'
371
vm_folder = 'folder-1'
372
vm_import_spec = None
374
fake_VmdkWriteHandle = mock.Mock()
375
fake_VmdkWriteHandle.get_imported_vm = mock.Mock()
376
fake_rw_handles_VmdkWriteHandle.return_value = fake_VmdkWriteHandle
378
image_transfer.download_stream_optimized_data(
385
resource_pool=resource_pool,
387
vm_import_spec=vm_import_spec,
388
image_size=image_size)
390
fake_rw_handles_VmdkWriteHandle.assert_called_once_with(
399
fake_transfer.assert_called_once_with(
404
write_file_handle=fake_VmdkWriteHandle)
406
fake_VmdkWriteHandle.get_imported_vm.assert_called_once()
408
@mock.patch('oslo_vmware.rw_handles.ImageReadHandle')
409
@mock.patch.object(image_transfer, 'download_stream_optimized_data')
410
def test_download_stream_optimized_image(
411
self, fake_download_stream_optimized_data,
412
fake_rw_handles_ImageReadHandle):
414
context = mock.Mock()
415
session = mock.Mock()
416
image_id = mock.Mock()
421
resource_pool = 'rp-1'
422
vm_folder = 'folder-1'
423
vm_import_spec = None
425
fake_iter = 'fake_iter'
426
image_service = mock.Mock()
427
image_service.download = mock.Mock()
428
image_service.download.return_value = fake_iter
430
fake_ImageReadHandle = 'fake_ImageReadHandle'
431
fake_rw_handles_ImageReadHandle.return_value = fake_ImageReadHandle
433
image_transfer.download_stream_optimized_image(
441
resource_pool=resource_pool,
443
vm_import_spec=vm_import_spec,
444
image_size=image_size)
446
image_service.download.assert_called_once_with(context, image_id)
448
fake_rw_handles_ImageReadHandle.assert_called_once_with(fake_iter)
450
fake_download_stream_optimized_data.assert_called_once_with(
453
fake_ImageReadHandle,
457
resource_pool=resource_pool,
459
vm_import_spec=vm_import_spec,
460
image_size=image_size)
462
@mock.patch.object(image_transfer, '_start_transfer')
463
@mock.patch('oslo_vmware.rw_handles.VmdkReadHandle')
464
def test_copy_stream_optimized_disk(
465
self, vmdk_read_handle, start_transfer):
467
read_handle = mock.sentinel.read_handle
468
vmdk_read_handle.return_value = read_handle
470
context = mock.sentinel.context
471
timeout = mock.sentinel.timeout
472
write_handle = mock.Mock(name='/cinder/images/tmpAbcd.vmdk')
473
session = mock.sentinel.session
474
host = mock.sentinel.host
475
port = mock.sentinel.port
476
vm = mock.sentinel.vm
477
vmdk_file_path = mock.sentinel.vmdk_file_path
478
vmdk_size = mock.sentinel.vmdk_size
480
image_transfer.copy_stream_optimized_disk(
481
context, timeout, write_handle, session=session, host=host,
482
port=port, vm=vm, vmdk_file_path=vmdk_file_path,
485
vmdk_read_handle.assert_called_once_with(
486
session, host, port, vm, vmdk_file_path, vmdk_size)
487
start_transfer.assert_called_once_with(
488
context, timeout, read_handle, vmdk_size,
489
write_file_handle=write_handle)
491
@mock.patch('oslo_vmware.rw_handles.VmdkReadHandle')
492
@mock.patch.object(image_transfer, '_start_transfer')
493
def test_upload_image(self, fake_transfer, fake_rw_handles_VmdkReadHandle):
495
context = mock.Mock()
496
image_id = mock.Mock()
497
owner_id = mock.Mock()
498
session = mock.Mock()
500
image_service = mock.Mock()
506
file_path = '/fake_path'
508
image_name = 'fake_image'
511
fake_VmdkReadHandle = 'fake_VmdkReadHandle'
512
fake_rw_handles_VmdkReadHandle.return_value = fake_VmdkReadHandle
514
image_transfer.upload_image(context,
523
vmdk_file_path=file_path,
524
vmdk_size=image_size,
526
image_name=image_name,
527
image_version=image_version)
529
fake_rw_handles_VmdkReadHandle.assert_called_once_with(session,
536
image_metadata = {'disk_format': 'vmdk',
537
'is_public': is_public,
540
'container_format': 'bare',
542
'properties': {'vmware_image_version': image_version,
543
'vmware_disktype': 'streamOptimized',
544
'owner_id': owner_id}}
546
fake_transfer.assert_called_once_with(context,
550
image_service=image_service,
552
image_meta=image_metadata)