# Copyright 2012 Michael Still and Canonical 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. import contextlib import io import os import time import mock from oslo_concurrency import lockutils from oslo_concurrency import processutils from oslo_log import formatters from oslo_log import log as logging from oslo_utils.fixture import uuidsentinel as uuids from nova.compute import manager as compute_manager import nova.conf from nova import context from nova import objects from nova import test from nova.tests.unit import fake_instance from nova import utils from nova.virt.libvirt import imagecache CONF = nova.conf.CONF @contextlib.contextmanager def intercept_log_messages(): try: mylog = logging.getLogger('nova') stream = io.StringIO() handler = logging.logging.StreamHandler(stream) handler.setFormatter(formatters.ContextFormatter()) mylog.logger.addHandler(handler) yield stream finally: mylog.logger.removeHandler(handler) class GetCacheFnameTestCase(test.NoDBTestCase): def test_get_cache_fname(self): # Ensure a known input to this function produces a known output. # This test assures us that, used in the expected manner, the function # doesn't raise an exception in either python2 or python3. It also # serves as a canary to warn if any change in underlying libraries # would produce output incompatible with current usage. # Take a known image_id and the pre-calculated hexdigest of its sha1 image_id = 'fd0cb2f1-8375-44c9-b1f4-3e1f4c4a8ef0' expected_cache_name = '0d5e6b61602d758984b3bf038267614d6016eb2a' cache_name = imagecache.get_cache_fname(image_id) self.assertEqual(expected_cache_name, cache_name) class ImageCacheManagerTestCase(test.NoDBTestCase): def setUp(self): super(ImageCacheManagerTestCase, self).setUp() self.stock_instance_names = set(['instance-00000001', 'instance-00000002', 'instance-00000003', 'banana-42-hamster']) @mock.patch.object(os.path, 'exists', return_value=True) @mock.patch.object(time, 'time', return_value=2000000) @mock.patch.object(os.path, 'getmtime', return_value=1000000) def test_get_age_of_file(self, mock_getmtime, mock_time, mock_exists): image_cache_manager = imagecache.ImageCacheManager() exists, age = image_cache_manager._get_age_of_file('/tmp') self.assertTrue(exists) self.assertEqual(1000000, age) @mock.patch.object(os.path, 'exists', return_value=False) def test_get_age_of_file_not_exists(self, mock_exists): image_cache_manager = imagecache.ImageCacheManager() exists, age = image_cache_manager._get_age_of_file('/tmp') self.assertFalse(exists) self.assertEqual(0, age) def test_list_base_images(self): listing = ['00000001', 'ephemeral_20_abcdefg', '00000004', 'swap_1000'] images = ['e97222e91fc4241f49a7f520d1dcf446751129b3_sm', 'e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm', 'e97222e91fc4241f49a7f520d1dcf446751129b3', '17d1b00b81642842e514494a78e804e9a511637c', '17d1b00b81642842e514494a78e804e9a511637c_5368709120', '17d1b00b81642842e514494a78e804e9a511637c_10737418240'] listing.extend(images) self.stub_out('os.listdir', lambda x: listing) self.stub_out('os.path.isfile', lambda x: True) base_dir = '/var/lib/nova/instances/_base' self.flags(instances_path='/var/lib/nova/instances') image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._scan_base_images(base_dir) sanitized = [] for ent in image_cache_manager.unexplained_images: sanitized.append(ent.replace(base_dir + '/', '')) self.assertEqual(sorted(sanitized), sorted(images)) expected = os.path.join(base_dir, 'e97222e91fc4241f49a7f520d1dcf446751129b3') self.assertIn(expected, image_cache_manager.unexplained_images) expected = os.path.join(base_dir, '17d1b00b81642842e514494a78e804e9a511637c_' '10737418240') self.assertIn(expected, image_cache_manager.unexplained_images) unexpected = os.path.join(base_dir, '00000004') self.assertNotIn(unexpected, image_cache_manager.unexplained_images) for ent in image_cache_manager.unexplained_images: self.assertTrue(ent.startswith(base_dir)) self.assertEqual(len(image_cache_manager.originals), 2) expected = os.path.join(base_dir, '17d1b00b81642842e514494a78e804e9a511637c') self.assertIn(expected, image_cache_manager.originals) unexpected = os.path.join(base_dir, '17d1b00b81642842e514494a78e804e9a511637c_' '10737418240') self.assertNotIn(unexpected, image_cache_manager.originals) self.assertEqual(1, len(image_cache_manager.back_swap_images)) self.assertIn('swap_1000', image_cache_manager.back_swap_images) self.assertEqual(1, len(image_cache_manager.back_ephemeral_images)) self.assertIn( 'ephemeral_20_abcdefg', image_cache_manager.back_ephemeral_images) def test_list_backing_images_small(self): self.stub_out('os.listdir', lambda x: ['_base', 'instance-00000001', 'instance-00000002', 'instance-00000003']) self.stub_out('os.path.exists', lambda x: x.find('instance-') != -1) self.stub_out('nova.virt.libvirt.utils.get_disk_backing_file', lambda x: 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm') found = os.path.join(CONF.instances_path, CONF.image_cache.subdirectory_name, 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm') image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.unexplained_images = [found] image_cache_manager.instance_names = self.stock_instance_names inuse_images = image_cache_manager._list_backing_images() self.assertEqual(inuse_images, [found]) self.assertEqual(len(image_cache_manager.unexplained_images), 0) def test_list_backing_images_resized(self): self.stub_out('os.listdir', lambda x: ['_base', 'instance-00000001', 'instance-00000002', 'instance-00000003']) self.stub_out('os.path.exists', lambda x: x.find('instance-') != -1) self.stub_out('nova.virt.libvirt.utils.get_disk_backing_file', lambda x: ('e97222e91fc4241f49a7f520d1dcf446751129b3_' '10737418240')) found = os.path.join(CONF.instances_path, CONF.image_cache.subdirectory_name, 'e97222e91fc4241f49a7f520d1dcf446751129b3_' '10737418240') image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.unexplained_images = [found] image_cache_manager.instance_names = self.stock_instance_names inuse_images = image_cache_manager._list_backing_images() self.assertEqual(inuse_images, [found]) self.assertEqual(len(image_cache_manager.unexplained_images), 0) def test_list_backing_images_instancename(self): self.stub_out('os.listdir', lambda x: ['_base', 'banana-42-hamster']) self.stub_out('os.path.exists', lambda x: x.find('banana-42-hamster') != -1) self.stub_out('nova.virt.libvirt.utils.get_disk_backing_file', lambda x: 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm') found = os.path.join(CONF.instances_path, CONF.image_cache.subdirectory_name, 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm') image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.unexplained_images = [found] image_cache_manager.instance_names = self.stock_instance_names inuse_images = image_cache_manager._list_backing_images() self.assertEqual(inuse_images, [found]) self.assertEqual(len(image_cache_manager.unexplained_images), 0) def test_list_backing_images_disk_notexist(self): self.stub_out('os.listdir', lambda x: ['_base', 'banana-42-hamster']) self.stub_out('os.path.exists', lambda x: x.find('banana-42-hamster') != -1) def fake_get_disk(disk_path): raise processutils.ProcessExecutionError() self.stub_out('nova.virt.libvirt.utils.get_disk_backing_file', fake_get_disk) image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.unexplained_images = [] image_cache_manager.instance_names = self.stock_instance_names self.assertRaises(processutils.ProcessExecutionError, image_cache_manager._list_backing_images) def test_find_base_file_nothing(self): self.stub_out('os.path.exists', lambda x: False) base_dir = '/var/lib/nova/instances/_base' fingerprint = '549867354867' image_cache_manager = imagecache.ImageCacheManager() res = list(image_cache_manager._find_base_file(base_dir, fingerprint)) self.assertEqual(0, len(res)) def test_find_base_file_small(self): fingerprint = '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a' self.stub_out('os.path.exists', lambda x: x.endswith('%s_sm' % fingerprint)) base_dir = '/var/lib/nova/instances/_base' image_cache_manager = imagecache.ImageCacheManager() res = list(image_cache_manager._find_base_file(base_dir, fingerprint)) base_file = os.path.join(base_dir, fingerprint + '_sm') self.assertEqual([base_file], res) def test_find_base_file_resized(self): fingerprint = '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a' listing = ['00000001', 'ephemeral_0_20_None', '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a_10737418240', '00000004'] self.stub_out('os.listdir', lambda x: listing) self.stub_out('os.path.exists', lambda x: x.endswith('%s_10737418240' % fingerprint)) self.stub_out('os.path.isfile', lambda x: True) base_dir = '/var/lib/nova/instances/_base' image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._scan_base_images(base_dir) res = list(image_cache_manager._find_base_file(base_dir, fingerprint)) base_file = os.path.join(base_dir, fingerprint + '_10737418240') self.assertEqual([base_file], res) def test_find_base_file_all(self): fingerprint = '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a' listing = ['00000001', 'ephemeral_0_20_None', '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a_sm', '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a_10737418240', '00000004'] self.stub_out('os.listdir', lambda x: listing) self.stub_out('os.path.exists', lambda x: True) self.stub_out('os.path.isfile', lambda x: True) base_dir = '/var/lib/nova/instances/_base' image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._scan_base_images(base_dir) res = list(image_cache_manager._find_base_file(base_dir, fingerprint)) base_file1 = os.path.join(base_dir, fingerprint) base_file2 = os.path.join(base_dir, fingerprint + '_sm') base_file3 = os.path.join(base_dir, fingerprint + '_10737418240') self.assertEqual([base_file1, base_file2, base_file3], res) @contextlib.contextmanager def _make_base_file(self, lock=True): """Make a base file for testing.""" with utils.tempdir() as tmpdir: self.flags(instances_path=tmpdir) fname = os.path.join(tmpdir, 'aaa') base_file = open(fname, 'w') base_file.write('data') base_file.close() if lock: lockdir = os.path.join(tmpdir, 'locks') lockname = os.path.join(lockdir, 'nova-aaa') os.mkdir(lockdir) lock_file = open(lockname, 'w') lock_file.write('data') lock_file.close() base_file = open(fname, 'r') base_file.close() yield fname def test_remove_base_file(self): with self._make_base_file() as fname: image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._remove_base_file(fname) lock_name = 'nova-' + os.path.split(fname)[-1] lock_dir = os.path.join(CONF.instances_path, 'locks') lock_file = os.path.join(lock_dir, lock_name) # Files are initially too new to delete self.assertTrue(os.path.exists(fname)) self.assertTrue(os.path.exists(lock_file)) # Old files get cleaned up though os.utime(fname, (-1, time.time() - 3601)) image_cache_manager._remove_base_file(fname) self.assertFalse(os.path.exists(fname)) self.assertFalse(os.path.exists(lock_file)) def test_remove_base_file_original(self): with self._make_base_file() as fname: image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.originals = [fname] image_cache_manager._remove_base_file(fname) # Files are initially too new to delete self.assertTrue(os.path.exists(fname)) # This file should stay longer than a resized image os.utime(fname, (-1, time.time() - 3601)) image_cache_manager._remove_base_file(fname) self.assertTrue(os.path.exists(fname)) # Originals don't stay forever though os.utime(fname, (-1, time.time() - 3600 * 25)) image_cache_manager._remove_base_file(fname) self.assertFalse(os.path.exists(fname)) def test_remove_base_file_dne(self): # This test is solely to execute the "does not exist" code path. We # don't expect the method being tested to do anything in this case. with utils.tempdir() as tmpdir: self.flags(instances_path=tmpdir) fname = os.path.join(tmpdir, 'aaa') image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._remove_base_file(fname) def test_remove_base_file_oserror(self): with intercept_log_messages() as stream: with utils.tempdir() as tmpdir: self.flags(instances_path=tmpdir) fname = os.path.join(tmpdir, 'aaa') os.mkdir(fname) os.utime(fname, (-1, time.time() - 3601)) # This will raise an OSError because of file permissions image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._remove_base_file(fname) self.assertTrue(os.path.exists(fname)) self.assertNotEqual(stream.getvalue().find('Failed to remove'), -1) @mock.patch('nova.privsep.path.utime') def test_mark_in_use(self, mock_utime): img = '123' with self._make_base_file() as fname: image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.unexplained_images = [fname] image_cache_manager.used_images = {'123': (1, 0, ['banana-42'])} image_cache_manager._mark_in_use(img, fname) mock_utime.assert_called_once_with(fname) self.assertEqual(image_cache_manager.unexplained_images, []) self.assertEqual(image_cache_manager.removable_base_files, []) @mock.patch('nova.privsep.path.utime') @mock.patch.object(lockutils, 'external_lock') def test_verify_base_images(self, mock_lock, mock_utime): hashed_1 = '356a192b7913b04c54574d18c28d46e6395428ab' hashed_21 = '472b07b9fcf2c2451e8781e944bf5f77cd8457c8' hashed_22 = '12c6fc06c99a462375eeb3f43dfd832b08ca9e17' hashed_42 = '92cfceb39d57d914ed8b14d0e37643de0797ae56' self.flags(instances_path='/instance_path') self.flags(subdirectory_name='_base', group='image_cache') base_file_list = ['00000001', 'ephemeral_0_20_None', 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm', 'e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm', hashed_42, hashed_1, hashed_21, hashed_22, '%s_5368709120' % hashed_1, '%s_10737418240' % hashed_1, '00000004'] def fq_path(path): return os.path.join('/instance_path/_base/', path) # Fake base directory existence orig_exists = os.path.exists def exists(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_exists(path) if path in ['/instance_path', '/instance_path/_base', '/instance_path/instance-1/disk', '/instance_path/instance-2/disk', '/instance_path/instance-3/disk']: return True for p in base_file_list: if path == fq_path(p): return True if path in ['/instance_path/_base/%s_sm' % i for i in [hashed_1, hashed_21, hashed_22, hashed_42]]: return False self.fail('Unexpected path existence check: %s' % path) self.stub_out('os.path.exists', lambda x: exists(x)) # Fake up some instances in the instances directory orig_listdir = os.listdir def listdir(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_listdir(path) if path == '/instance_path': return ['instance-1', 'instance-2', 'instance-3', '_base'] if path == '/instance_path/_base': return base_file_list self.fail('Unexpected directory listed: %s' % path) self.stub_out('os.listdir', lambda x: listdir(x)) # Fake isfile for these faked images in _base orig_isfile = os.path.isfile def isfile(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_isfile(path) for p in base_file_list: if path == fq_path(p): return True self.fail('Unexpected isfile call: %s' % path) self.stub_out('os.path.isfile', lambda x: isfile(x)) # Fake the database call which lists running instances instances = [{'image_ref': '1', 'host': CONF.host, 'name': 'instance-1', 'uuid': uuids.instance_1, 'vm_state': '', 'task_state': ''}, {'image_ref': '1', 'kernel_id': '21', 'ramdisk_id': '22', 'host': CONF.host, 'name': 'instance-2', 'uuid': uuids.instance_2, 'vm_state': '', 'task_state': ''}] all_instances = [fake_instance.fake_instance_obj(None, **instance) for instance in instances] image_cache_manager = imagecache.ImageCacheManager() # Fake the utils call which finds the backing image def get_disk_backing_file(path): if path in ['/instance_path/instance-1/disk', '/instance_path/instance-2/disk']: return fq_path('%s_5368709120' % hashed_1) self.fail('Unexpected backing file lookup: %s' % path) self.stub_out('nova.virt.libvirt.utils.get_disk_backing_file', lambda x: get_disk_backing_file(x)) # Fake getmtime as well orig_getmtime = os.path.getmtime def getmtime(path): if not path.startswith('/instance_path'): return orig_getmtime(path) return 1000000 self.stub_out('os.path.getmtime', lambda x: getmtime(x)) # Make sure we don't accidentally remove a real file orig_remove = os.remove def remove(path): if not path.startswith('/instance_path'): return orig_remove(path) # Don't try to remove fake files return self.stub_out('os.remove', lambda x: remove(x)) with mock.patch.object(objects.block_device.BlockDeviceMappingList, 'bdms_by_instance_uuid', return_value={} ) as mock_bdms: ctxt = context.get_admin_context() # And finally we can make the call we're actually testing... # The argument here should be a context, but it is mocked out image_cache_manager.update(ctxt, all_instances) # Verify active = [fq_path(hashed_1), fq_path('%s_5368709120' % hashed_1), fq_path(hashed_21), fq_path(hashed_22)] for act in active: self.assertIn(act, image_cache_manager.active_base_files) self.assertEqual(len(image_cache_manager.active_base_files), len(active)) for rem in [fq_path('e97222e91fc4241f49a7f520d1dcf446751129b3_sm'), fq_path('e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm'), fq_path(hashed_42), fq_path('%s_10737418240' % hashed_1)]: self.assertIn(rem, image_cache_manager.removable_base_files) mock_bdms.assert_called_once_with(ctxt, [uuids.instance_1, uuids.instance_2]) def test_verify_base_images_no_base(self): self.flags(instances_path='/tmp/no/such/dir/name/please') image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.update(None, []) @mock.patch('nova.objects.InstanceList.get_by_filters') def test_run_image_cache_manager_pass(self, mock_instance_list): def fake_instances(ctxt): instances = [] for x in range(2): instances.append( fake_instance.fake_db_instance( image_ref=uuids.fake_image_ref, uuid=getattr(uuids, 'instance_%s' % x), name='instance-%s' % x, vm_state='', task_state='')) return objects.instance._make_instance_list( ctxt, objects.InstanceList(), instances, None) with utils.tempdir() as tmpdir: self.flags(instances_path=tmpdir) ctxt = context.get_admin_context() mock_instance_list.return_value = fake_instances(ctxt) compute = compute_manager.ComputeManager() compute._run_image_cache_manager_pass(ctxt) filters = { 'host': ['fake-mini'], 'deleted': False, 'soft_deleted': True, } mock_instance_list.assert_called_once_with( ctxt, filters, expected_attrs=[], use_slave=True) def test_store_swap_image(self): image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._store_swap_image('swap_') image_cache_manager._store_swap_image('swap_123') image_cache_manager._store_swap_image('swap_456') image_cache_manager._store_swap_image('swap_abc') image_cache_manager._store_swap_image('123_swap') image_cache_manager._store_swap_image('swap_129_') self.assertEqual(len(image_cache_manager.back_swap_images), 2) expect_set = set(['swap_123', 'swap_456']) self.assertEqual(image_cache_manager.back_swap_images, expect_set) def test_store_ephemeral_image(self): image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._store_ephemeral_image('ephemeral_') image_cache_manager._store_ephemeral_image('ephemeral_123') image_cache_manager._store_ephemeral_image('ephemeral_456_40d1d2c') image_cache_manager._store_ephemeral_image('ephemeral_abc_40d1f2e') image_cache_manager._store_ephemeral_image('123_ephemeral_40e1d2d') image_cache_manager._store_ephemeral_image('ephemeral_129_') self.assertEqual(len(image_cache_manager.back_ephemeral_images), 1) expect_set = set(['ephemeral_456_40d1d2c']) self.assertEqual(image_cache_manager.back_ephemeral_images, expect_set) @mock.patch.object(lockutils, 'external_lock') @mock.patch('os.path.exists') @mock.patch('os.path.getmtime') @mock.patch('os.remove') @mock.patch('nova.privsep.path.utime') def test_age_and_verify_swap_images(self, mock_utime, mock_remove, mock_getmtime, mock_exist, mock_lock): base_dir = '/tmp_age_test' image_cache_manager = imagecache.ImageCacheManager() expected_remove = set() expected_exist = set(['swap_128', 'swap_256']) image_cache_manager.back_swap_images.add('swap_128') image_cache_manager.back_swap_images.add('swap_256') image_cache_manager.used_swap_images.add('swap_128') mock_getmtime.side_effect = lambda path: time.time() - 1000000 mock_exist.side_effect = \ lambda path: os.path.dirname(path) == base_dir and \ os.path.basename(path) in expected_exist def removefile(path): self.assertEqual(base_dir, os.path.dirname(path), 'Attempt to remove unexpected path') fn = os.path.basename(path) expected_remove.add(fn) expected_exist.remove(fn) mock_remove.side_effect = removefile image_cache_manager._age_and_verify_swap_images(None, base_dir) self.assertEqual(set(['swap_128']), expected_exist) self.assertEqual(set(['swap_256']), expected_remove) @mock.patch.object(lockutils, 'external_lock') @mock.patch('os.path.exists') @mock.patch('os.path.getmtime') @mock.patch('os.remove') @mock.patch('nova.privsep.path.utime') def test_age_and_verify_ephemeral_images(self, mock_utime, mock_remove, mock_getmtime, mock_exist, mock_lock): base_dir = '/tmp_age_test' image_cache_manager = imagecache.ImageCacheManager() expected_remove = set() expected_exist = set(['ephemeral_456_40d1d2c', 'ephemeral_2_41e1f2c']) image_cache_manager.back_ephemeral_images.add('ephemeral_456_40d1d2c') image_cache_manager.back_ephemeral_images.add('ephemeral_2_41e1f2c') image_cache_manager.used_ephemeral_images.add('ephemeral_2_41e1f2c') mock_getmtime.side_effect = lambda path: time.time() - 1000000 mock_exist.side_effect = \ lambda path: os.path.dirname(path) == base_dir and \ os.path.basename(path) in expected_exist def removefile(path): self.assertEqual(base_dir, os.path.dirname(path), 'Attempt to remove unexpected path') fn = os.path.basename(path) expected_remove.add(fn) expected_exist.remove(fn) mock_remove.side_effect = removefile image_cache_manager._age_and_verify_ephemeral_images(None, base_dir) self.assertEqual(set(['ephemeral_2_41e1f2c']), expected_exist) self.assertEqual(set(['ephemeral_456_40d1d2c']), expected_remove) @mock.patch.object(utils, 'synchronized') @mock.patch.object(imagecache.ImageCacheManager, '_get_age_of_file', return_value=(True, 100)) def test_lock_acquired_on_removing_old_enough_files(self, mock_get_age, mock_synchronized): base_file = '/tmp_age_test' lock_path = os.path.join(CONF.instances_path, 'locks') lock_file = os.path.split(base_file)[-1] image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._remove_old_enough_file(base_file, 60, remove_lock=False) mock_synchronized.assert_called_once_with(lock_file, external=True, lock_path=lock_path) @mock.patch('os.stat') def test_get_disk_usage_cache_is_on_different_disk(self, mock_stat): mock_stat.side_effect = [mock.Mock(st_dev=0), mock.Mock(st_dev=1)] manager = imagecache.ImageCacheManager() self.assertEqual(0, manager.get_disk_usage()) mock_stat.assert_has_calls([ mock.call(CONF.instances_path), mock.call( os.path.join( CONF.instances_path, CONF.image_cache.subdirectory_name))]) @mock.patch('os.listdir') @mock.patch('os.stat') def test_get_disk_usage_empty(self, mock_stat, mock_listdir): mock_stat.side_effect = [mock.Mock(st_dev=0), mock.Mock(st_dev=0)] mock_listdir.return_value = [] manager = imagecache.ImageCacheManager() self.assertEqual(0, manager.get_disk_usage()) @mock.patch('os.stat') @mock.patch('os.listdir') def test_get_disk_usage_cache_dir_missing(self, mock_listdir, mock_stat): mock_stat.side_effect = [mock.Mock(st_dev=0), FileNotFoundError] manager = imagecache.ImageCacheManager() self.assertEqual(0, manager.get_disk_usage()) mock_listdir.assert_not_called() @mock.patch('os.path.isfile') @mock.patch('os.listdir') @mock.patch('os.stat') def test_get_disk_usage(self, mock_stat, mock_listdir, mock_isfile): mock_stat.side_effect = [ # cache and instances dirs are on the same dev mock.Mock(st_dev=0), mock.Mock(st_dev=0), # stat calls on each file in the cache directory to get the size mock.Mock(st_blocks=10), # foo mock.Mock(st_blocks=20), # bar ] mock_listdir.return_value = ['foo', 'bar', 'some-dir'] mock_isfile.side_effect = [ True, # foo True, # bar False, # some-dir ] manager = imagecache.ImageCacheManager() # size is calculated from as st_blocks * 512 self.assertEqual(10 * 512 + 20 * 512, manager.get_disk_usage()) @mock.patch('os.path.isfile') @mock.patch('os.listdir') @mock.patch('os.stat') def test_get_disk_usage_io_error_while_reading( self, mock_stat, mock_listdir, mock_isfile): mock_stat.side_effect = [ # cache and instances dirs are on the same dev mock.Mock(st_dev=0), mock.Mock(st_dev=0), # stat calls on each file in the cache directory to get the size mock.Mock(st_blocks=10), # foo IOError, # error while checking bar ] mock_listdir.return_value = ['foo', 'bar', 'some-dir'] mock_isfile.side_effect = [ True, # foo True, # bar False, # some-dir ] manager = imagecache.ImageCacheManager() self.assertEqual(0, manager.get_disk_usage())