summaryrefslogtreecommitdiff
path: root/tests/unittests/test_clear_holders.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unittests/test_clear_holders.py')
-rw-r--r--tests/unittests/test_clear_holders.py351
1 files changed, 48 insertions, 303 deletions
diff --git a/tests/unittests/test_clear_holders.py b/tests/unittests/test_clear_holders.py
index 10ea1abc..e4d8f8d6 100644
--- a/tests/unittests/test_clear_holders.py
+++ b/tests/unittests/test_clear_holders.py
@@ -1,9 +1,9 @@
# This file is part of curtin. See LICENSE file for copyright and license info.
-import errno
import mock
import os
import textwrap
+import uuid
from curtin.block import clear_holders
from curtin.util import ProcessExecutionError
@@ -89,30 +89,6 @@ class TestClearHolders(CiTestCase):
self.assertEqual(res, uuid)
mock_block.sysfs_to_devpath.assert_called_with(self.test_syspath)
- @mock.patch('curtin.block.clear_holders.block')
- @mock.patch('curtin.block.clear_holders.os')
- def test_get_bcache_using_dev(self, mock_os, mock_block):
- """Ensure that get_bcache_using_dev works"""
- fake_bcache = '/sys/fs/bcache/fake'
- mock_os.path.join.side_effect = os.path.join
- mock_block.sys_block_path.return_value = self.test_syspath
- mock_os.path.realpath.return_value = fake_bcache
-
- bcache_dir = clear_holders.get_bcache_using_dev(self.test_blockdev)
- mock_os.path.realpath.assert_called_with(self.test_syspath +
- '/bcache/cache')
- self.assertEqual(bcache_dir, fake_bcache)
-
- @mock.patch('curtin.block.clear_holders.os')
- @mock.patch('curtin.block.clear_holders.block')
- def test_get_bcache_sys_path(self, mock_block, mock_os):
- fake_backing = '/sys/class/block/fake'
- mock_block.sys_block_path.return_value = fake_backing
- mock_os.path.join.side_effect = os.path.join
- mock_os.path.exists.return_value = True
- bcache_dir = clear_holders.get_bcache_sys_path("/dev/fake")
- self.assertEqual(bcache_dir, fake_backing + "/bcache")
-
@mock.patch('curtin.block.clear_holders.get_dmsetup_uuid')
@mock.patch('curtin.block.clear_holders.block')
def test_differentiate_lvm_and_crypt(
@@ -133,264 +109,68 @@ class TestClearHolders(CiTestCase):
mock_block.path_to_kname.assert_called_with(self.test_syspath)
mock_get_dmsetup_uuid.assert_called_with(self.test_syspath)
- @mock.patch('curtin.block.clear_holders.block')
- @mock.patch('curtin.block.clear_holders.udev.udevadm_settle')
- @mock.patch('curtin.block.clear_holders.get_bcache_sys_path')
- @mock.patch('curtin.block.clear_holders.util')
@mock.patch('curtin.block.clear_holders.os')
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.get_bcache_using_dev')
- def test_shutdown_bcache(self, mock_get_bcache, mock_log, mock_os,
- mock_util, mock_get_bcache_block,
- mock_udevadm_settle, mock_block):
+ @mock.patch('curtin.block.clear_holders.util')
+ @mock.patch('curtin.block.clear_holders.udev')
+ @mock.patch('curtin.block.clear_holders.block')
+ @mock.patch('curtin.block.clear_holders.bcache')
+ def test_shutdown_bcache(self, m_bcache, m_block, m_udev, m_util, m_os):
"""test clear_holders.shutdown_bcache"""
- #
- # pass in a sysfs path to a bcache block device,
- # determine the bcache cset it is part of (or not)
- # 1) stop the cset device (if it's enabled)
- # 2) wait on cset to be removed if it was present
- # 3) stop the block device (if it's still present after stopping cset)
- # 4) wait on bcache block device to be removed
- #
-
device = self.test_syspath
- mock_block.sys_block_path.return_value = self.test_blockdev
- bcache_cset_uuid = 'c08ae789-a964-46fb-a66e-650f0ae78f94'
-
- mock_os.path.exists.return_value = True
- mock_os.path.join.side_effect = os.path.join
- # os.path.realpath on symlink of /sys/class/block/null/bcache/cache ->
- # to /sys/fs/bcache/cset_UUID
- mock_get_bcache.return_value = '/sys/fs/bcache/' + bcache_cset_uuid
- mock_get_bcache_block.return_value = device + '/bcache'
+ backing_dev = 'backing1'
+ backing_sys = '/sys/class/block/%s' % backing_dev
+ m_block.sysfs_to_devpath.return_value = self.test_blockdev
+ cset_uuid = str(uuid.uuid4())
+
+ def my_sysblock(p, strict=False):
+ return '/sys/class/block/%s' % os.path.basename(p)
+
+ def my_bsys(p, strict=False):
+ return my_sysblock(p, strict=strict) + '/bcache'
+
+ m_bcache.sysfs_path.side_effect = my_bsys
+ m_os.path.join.side_effect = os.path.join
+ m_os.listdir.return_value = [backing_dev]
+ m_os.path.exists.return_value = True
+ m_bcache.get_attached_cacheset.return_value = cset_uuid
+ m_block.path_to_kname.return_value = self.test_blockdev
+ m_bcache.get_backing_device.return_value = backing_sys + '/bcache'
+ m_bcache.get_cacheset_members.return_value = []
clear_holders.shutdown_bcache(device)
- mock_get_bcache.assert_called_with(device, strict=False)
- mock_get_bcache_block.assert_called_with(device, strict=False)
-
- self.assertTrue(mock_log.info.called)
- self.assertFalse(mock_log.warn.called)
- mock_util.wait_for_removal.assert_has_calls([
- mock.call('/sys/fs/bcache/' + bcache_cset_uuid,
- retries=self.remove_retries),
- mock.call(device, retries=self.remove_retries)])
-
- mock_util.write_file.assert_has_calls([
- mock.call('/sys/fs/bcache/%s/stop' % bcache_cset_uuid,
- '1', mode=None),
- mock.call(device + '/bcache/stop',
- '1', mode=None)])
-
- @mock.patch('curtin.block.clear_holders.get_bcache_sys_path')
- @mock.patch('curtin.block.clear_holders.util')
- @mock.patch('curtin.block.clear_holders.os')
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.get_bcache_using_dev')
- def test_shutdown_bcache_non_sysfs_device(self, mock_get_bcache, mock_log,
- mock_os, mock_util,
- mock_get_bcache_block):
- with self.assertRaises(ValueError):
- clear_holders.shutdown_bcache(self.test_blockdev)
-
- self.assertEqual(0, len(mock_get_bcache.call_args_list))
- self.assertEqual(0, len(mock_log.call_args_list))
- self.assertEqual(0, len(mock_os.call_args_list))
- self.assertEqual(0, len(mock_util.call_args_list))
- self.assertEqual(0, len(mock_get_bcache_block.call_args_list))
-
- @mock.patch('curtin.block.clear_holders.block')
- @mock.patch('curtin.block.clear_holders.get_bcache_sys_path')
- @mock.patch('curtin.block.clear_holders.util')
- @mock.patch('curtin.block.clear_holders.os')
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.get_bcache_using_dev')
- def test_shutdown_bcache_no_device(self, mock_get_bcache, mock_log,
- mock_os, mock_util,
- mock_get_bcache_block, mock_block):
- mock_block.sysfs_to_devpath.return_value = self.test_blockdev
- mock_os.path.exists.return_value = False
-
- clear_holders.shutdown_bcache(self.test_syspath)
-
- self.assertEqual(3, len(mock_log.info.call_args_list))
- self.assertEqual(1, len(mock_os.path.exists.call_args_list))
- self.assertEqual(0, len(mock_get_bcache.call_args_list))
- self.assertEqual(0, len(mock_util.call_args_list))
- self.assertEqual(0, len(mock_get_bcache_block.call_args_list))
-
- @mock.patch('curtin.block.clear_holders.block')
- @mock.patch('curtin.block.clear_holders.get_bcache_sys_path')
- @mock.patch('curtin.block.clear_holders.util')
- @mock.patch('curtin.block.clear_holders.os')
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.get_bcache_using_dev')
- def test_shutdown_bcache_no_cset(self, mock_get_bcache, mock_log,
- mock_os, mock_util,
- mock_get_bcache_block, mock_block):
- mock_block.sysfs_to_devpath.return_value = self.test_blockdev
- mock_os.path.exists.side_effect = iter([
- True, # backing device exists
- False, # cset device not present (already removed)
- True, # backing device (still) exists
+ # 1. wipe the bcache device contents
+ m_block.wipe_volume.assert_called_with(self.test_blockdev,
+ mode='superblock',
+ exclusive=False,
+ strict=True)
+ # 2. extract the backing device
+ m_bcache.get_backing_device.assert_called_with(self.test_blockdev)
+ m_bcache.sysfs_path.assert_has_calls([
+ mock.call(self.test_syspath, strict=False),
])
- mock_get_bcache.return_value = '/sys/fs/bcache/fake'
- mock_get_bcache_block.return_value = self.test_syspath + '/bcache'
- mock_os.path.join.side_effect = os.path.join
-
- clear_holders.shutdown_bcache(self.test_syspath)
- self.assertEqual(4, len(mock_log.info.call_args_list))
- self.assertEqual(3, len(mock_os.path.exists.call_args_list))
- self.assertEqual(1, len(mock_get_bcache.call_args_list))
- self.assertEqual(1, len(mock_get_bcache_block.call_args_list))
- self.assertEqual(1, len(mock_util.write_file.call_args_list))
- self.assertEqual(2, len(mock_util.wait_for_removal.call_args_list))
-
- mock_get_bcache.assert_called_with(self.test_syspath, strict=False)
- mock_get_bcache_block.assert_called_with(self.test_syspath,
- strict=False)
- mock_util.write_file.assert_called_with(
- self.test_syspath + '/bcache/stop', '1', mode=None)
- retries = self.remove_retries
- mock_util.wait_for_removal.assert_has_calls([
- mock.call(self.test_syspath, retries=retries),
- mock.call(self.test_syspath + '/bcache', retries=retries)])
+ # 3. extract the cacheset uuid
+ m_bcache.get_attached_cacheset.assert_called_with(device)
- @mock.patch('curtin.block.clear_holders.block')
- @mock.patch('curtin.block.clear_holders.udev.udevadm_settle')
- @mock.patch('curtin.block.clear_holders.get_bcache_sys_path')
- @mock.patch('curtin.block.clear_holders.util')
- @mock.patch('curtin.block.clear_holders.os')
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.get_bcache_using_dev')
- def test_shutdown_bcache_delete_cset_and_backing(self, mock_get_bcache,
- mock_log, mock_os,
- mock_util,
- mock_get_bcache_block,
- mock_udevadm_settle,
- mock_block):
- mock_block.sysfs_to_devpath.return_value = self.test_blockdev
- mock_os.path.exists.side_effect = iter([
- True, # backing device exists
- True, # cset device not present (already removed)
- True, # backing device (still) exists
- ])
- cset = '/sys/fs/bcache/fake'
- mock_get_bcache.return_value = cset
- mock_get_bcache_block.return_value = self.test_syspath + '/bcache'
- mock_os.path.join.side_effect = os.path.join
+ # 4. stop the cacheset
+ m_bcache.stop_cacheset.assert_called_with(cset_uuid)
- clear_holders.shutdown_bcache(self.test_syspath)
+ # 5. stop the bcacheN device
+ m_bcache.stop_device.assert_any_call(my_bsys(device))
- self.assertEqual(4, len(mock_log.info.call_args_list))
- self.assertEqual(3, len(mock_os.path.exists.call_args_list))
- self.assertEqual(1, len(mock_get_bcache.call_args_list))
- self.assertEqual(1, len(mock_get_bcache_block.call_args_list))
- self.assertEqual(2, len(mock_util.write_file.call_args_list))
- self.assertEqual(3, len(mock_util.wait_for_removal.call_args_list))
-
- mock_get_bcache.assert_called_with(self.test_syspath, strict=False)
- mock_get_bcache_block.assert_called_with(self.test_syspath,
- strict=False)
- mock_util.write_file.assert_has_calls([
- mock.call(cset + '/stop', '1', mode=None),
- mock.call(self.test_syspath + '/bcache/stop', '1', mode=None)])
- mock_util.wait_for_removal.assert_has_calls([
- mock.call(cset, retries=self.remove_retries),
- mock.call(self.test_syspath, retries=self.remove_retries)
- ])
+ def test_shutdown_bcache_non_sysfs_device(self):
+ """ raises ValueError if called on non-bcache device."""
+ with self.assertRaises(ValueError):
+ clear_holders.shutdown_bcache(self.test_blockdev)
- @mock.patch('curtin.block.clear_holders.block')
- @mock.patch('curtin.block.clear_holders.udev.udevadm_settle')
- @mock.patch('curtin.block.clear_holders.get_bcache_sys_path')
- @mock.patch('curtin.block.clear_holders.util')
@mock.patch('curtin.block.clear_holders.os')
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.get_bcache_using_dev')
- def test_shutdown_bcache_delete_cset_no_backing(self, mock_get_bcache,
- mock_log, mock_os,
- mock_util,
- mock_get_bcache_block,
- mock_udevadm_settle,
- mock_block):
- mock_block.sysfs_to_devpath.return_value = self.test_blockdev
- mock_os.path.exists.side_effect = iter([
- True, # backing device exists
- True, # cset device not present (already removed)
- False, # backing device is removed with cset
- ])
- cset = '/sys/fs/bcache/fake'
- mock_get_bcache.return_value = cset
- mock_get_bcache_block.return_value = self.test_syspath + '/bcache'
- mock_os.path.join.side_effect = os.path.join
-
- clear_holders.shutdown_bcache(self.test_syspath)
-
- self.assertEqual(4, len(mock_log.info.call_args_list))
- self.assertEqual(3, len(mock_os.path.exists.call_args_list))
- self.assertEqual(1, len(mock_get_bcache.call_args_list))
- self.assertEqual(1, len(mock_get_bcache_block.call_args_list))
- self.assertEqual(1, len(mock_util.write_file.call_args_list))
- self.assertEqual(1, len(mock_util.wait_for_removal.call_args_list))
-
- mock_get_bcache.assert_called_with(self.test_syspath, strict=False)
- mock_util.write_file.assert_has_calls([
- mock.call(cset + '/stop', '1', mode=None),
- ])
- mock_util.wait_for_removal.assert_has_calls([
- mock.call(cset, retries=self.remove_retries)
- ])
-
- # test bcache shutdown with 'stop' sysfs write failure
@mock.patch('curtin.block.clear_holders.block')
- @mock.patch('curtin.block.wipe_volume')
- @mock.patch('curtin.block.clear_holders.udev.udevadm_settle')
- @mock.patch('curtin.block.clear_holders.get_bcache_sys_path')
- @mock.patch('curtin.block.clear_holders.util')
- @mock.patch('curtin.block.clear_holders.os')
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.get_bcache_using_dev')
- def test_shutdown_bcache_stop_sysfs_write_fails(self, mock_get_bcache,
- mock_log, mock_os,
- mock_util,
- mock_get_bcache_block,
- mock_udevadm_settle,
- mock_wipe,
- mock_block):
- """Test writes sysfs write failures pass if file not present"""
- mock_block.sysfs_to_devpath.return_value = self.test_blockdev
- mock_os.path.exists.side_effect = iter([
- True, # backing device exists
- True, # cset device not present (already removed)
- False, # backing device is removed with cset
- False, # bcache/stop sysfs is missing (already removed)
- ])
- cset = '/sys/fs/bcache/fake'
- mock_get_bcache.return_value = cset
- mock_get_bcache_block.return_value = self.test_syspath + '/bcache'
- mock_os.path.join.side_effect = os.path.join
-
- # make writes to sysfs fail
- mock_util.write_file.side_effect = IOError(errno.ENOENT,
- "File not found")
-
+ def test_shutdown_bcache_no_device(self, m_block, m_os):
+ """ shutdown_bcache does nothing if target device is not present."""
+ m_os.path.exists.return_value = False
clear_holders.shutdown_bcache(self.test_syspath)
-
- self.assertEqual(4, len(mock_log.info.call_args_list))
- self.assertEqual(3, len(mock_os.path.exists.call_args_list))
- self.assertEqual(1, len(mock_get_bcache.call_args_list))
- self.assertEqual(1, len(mock_get_bcache_block.call_args_list))
- self.assertEqual(1, len(mock_util.write_file.call_args_list))
- self.assertEqual(1, len(mock_util.wait_for_removal.call_args_list))
-
- mock_get_bcache.assert_called_with(self.test_syspath, strict=False)
- mock_util.write_file.assert_has_calls([
- mock.call(cset + '/stop', '1', mode=None),
- ])
- mock_util.wait_for_removal.assert_has_calls([
- mock.call(cset, retries=self.remove_retries)
- ])
+ m_block.wipe_volume.assert_not_called()
@mock.patch('curtin.block.quick_zero')
@mock.patch('curtin.block.clear_holders.LOG')
@@ -757,41 +537,6 @@ class TestClearHolders(CiTestCase):
for tree, result in test_trees_and_results:
self.assertEqual(clear_holders.format_holders_tree(tree), result)
- @mock.patch('curtin.block.clear_holders.util.write_file')
- def test_maybe_stop_bcache_device_raises_errors(self, m_write_file):
- """Non-IO/OS exceptions are raised by maybe_stop_bcache_device."""
- m_write_file.side_effect = ValueError('Crazy Value Error')
- with self.assertRaises(ValueError) as cm:
- clear_holders.maybe_stop_bcache_device('does/not/matter')
- self.assertEqual('Crazy Value Error', str(cm.exception))
- self.assertEqual(
- mock.call('does/not/matter/stop', '1', mode=None),
- m_write_file.call_args)
-
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.util.write_file')
- def test_maybe_stop_bcache_device_handles_oserror(self, m_write_file,
- m_log):
- """When OSError.NOENT is raised, log the condition and move on."""
- m_write_file.side_effect = OSError(errno.ENOENT, 'Expected oserror')
- clear_holders.maybe_stop_bcache_device('does/not/matter')
- self.assertEqual(
- 'Error writing to bcache stop file %s, device removed: %s',
- m_log.debug.call_args[0][0])
- self.assertEqual('does/not/matter/stop', m_log.debug.call_args[0][1])
-
- @mock.patch('curtin.block.clear_holders.LOG')
- @mock.patch('curtin.block.clear_holders.util.write_file')
- def test_maybe_stop_bcache_device_handles_ioerror(self, m_write_file,
- m_log):
- """When IOError.NOENT is raised, log the condition and move on."""
- m_write_file.side_effect = IOError(errno.ENOENT, 'Expected ioerror')
- clear_holders.maybe_stop_bcache_device('does/not/matter')
- self.assertEqual(
- 'Error writing to bcache stop file %s, device removed: %s',
- m_log.debug.call_args[0][0])
- self.assertEqual('does/not/matter/stop', m_log.debug.call_args[0][1])
-
def test_get_holder_types(self):
"""test clear_holders.get_holder_types"""
test_trees_and_results = [