import mock
import subprocess
import testtools
from probert import dasd
from probert.tests import fakes
from probert.tests.helpers import random_string
# The tests parse canned dasdview output, and to be able to write
# tests one needs to simply know what the correct parsed values
# are. These helper functions help make the this dependence on outside
# knowledge a little clearer:
def update_probe_data(base, **kw):
r = base.copy()
r.update(kw)
return r
expected_probe_data = {
'/dev/dasdd': {
'blocksize': 4096,
'cylinders': 30051,
'disk_layout': 'cdl',
'name': '/dev/dasdd',
'tracks_per_cylinder': 15,
'type': 'ECKD',
},
'/dev/dasde': {
'blocksize': 512,
'cylinders': 10017,
'disk_layout': 'not-formatted',
'name': '/dev/dasde',
'tracks_per_cylinder': 15,
'type': 'ECKD',
},
}
class TestDasd(testtools.TestCase):
def _load_test_data(self, data_fname):
testfile = fakes.TEST_DATA + '/' + data_fname
with open(testfile, 'r') as fh:
return fh.read()
@mock.patch('probert.dasd.os.path.exists')
@mock.patch('probert.dasd.subprocess.run')
def test_dasdview_returns_stdout(self, m_run, m_exists):
devname = random_string()
dasdview_out = random_string()
cp = subprocess.CompletedProcess(args=['foo'], returncode=0,
stdout=dasdview_out.encode('utf-8'),
stderr="")
m_run.return_value = cp
m_exists.return_value = True
result = dasd.dasdview(devname)
self.assertEqual(dasdview_out, result)
m_run.assert_called_with(['dasdview', '--extended', devname],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL)
@mock.patch('probert.dasd.os.path.exists')
@mock.patch('probert.dasd.subprocess.run')
def test_dasdview_raises_valueerror(self, m_run, m_exists):
devname = random_string()
m_exists.return_value = False
self.assertRaises(ValueError, dasd.dasdview, devname)
self.assertEqual(0, m_run.call_count)
@mock.patch('probert.dasd.os.path.exists')
@mock.patch('probert.dasd.subprocess.run')
def test_dasdview_returns_none_on_subprocess_error(self, m_run, m_exists):
devname = random_string()
m_exists.return_value = True
m_run.side_effect = subprocess.CalledProcessError(
cmd=[random_string()], returncode=1)
self.assertEqual(None, dasd.dasdview(devname))
def test_dasd_parses_blocksize(self):
self.assertEqual(
4096,
dasd.find_val_int(
dasd.DASD_BLKSIZE, self._load_test_data('dasdd.view')))
def test_dasd_blocksize_returns_none_on_invalid_output(self):
self.assertIsNone(
dasd.find_val_int(
dasd.DASD_BLKSIZE, random_string()))
def test_dasd_parses_disk_format(self):
self.assertEqual('cdl',
dasd.disk_format(self._load_test_data('dasdd.view')))
self.assertEqual('not-formatted',
dasd.disk_format(self._load_test_data('dasde.view')))
def test_dasd_parses_disk_format_ldl(self):
output = "format : hex 1 dec 1 LDL formatted"
self.assertEqual('ldl', dasd.disk_format(output))
def test_dasd_disk_format_returns_none_on_invalid_output(self):
self.assertIsNone(dasd.disk_format(random_string()))
@mock.patch('probert.dasd.dasdview')
def test_get_dasd_info(self, m_dview):
devname = random_string()
id_path = random_string()
device = {'DEVNAME': devname, 'ID_PATH': 'ccw-' + id_path}
m_dview.return_value = self._load_test_data('dasdd.view')
self.assertEqual(
update_probe_data(
expected_probe_data['/dev/dasdd'],
name=devname, device_id=id_path),
dasd.get_dasd_info(device))
@mock.patch('probert.dasd.dasdview')
def test_get_dasd_info_returns_none_if_not_all(self, m_dview):
devname = random_string()
id_path = random_string()
device = {'DEVNAME': devname, 'ID_PATH': 'ccw-' + id_path}
m_dview.return_value = random_string()
self.assertIsNone(dasd.get_dasd_info(device))
@mock.patch('probert.dasd.find_val_int')
@mock.patch('probert.dasd.dasdview')
def test_get_dasd_info_returns_none_if_bad_blocksize(self, m_dview,
m_find_val_int):
devname = random_string()
id_path = random_string()
device = {'DEVNAME': devname, 'ID_PATH': 'ccw-' + id_path}
m_dview.return_value = self._load_test_data('dasdd.view')
m_find_val_int.return_value = None
self.assertIsNone(dasd.get_dasd_info(device))
@mock.patch('probert.dasd.disk_format')
@mock.patch('probert.dasd.dasdview')
def test_get_dasd_info_returns_none_if_bad_disk_format(self, m_dview,
m_disk):
devname = random_string()
id_path = random_string()
device = {'DEVNAME': devname, 'ID_PATH': 'ccw-' + id_path}
m_dview.return_value = self._load_test_data('dasdd.view')
m_disk.return_value = None
self.assertIsNone(dasd.get_dasd_info(device))
@mock.patch('probert.dasd.platform.machine')
def test_dasd_probe_returns_empty_dict_non_s390x_arch(self, m_machine):
machine = random_string()
self.assertNotEqual("s390x", machine)
m_machine.return_value = machine
self.assertEqual({}, dasd.probe())
@mock.patch('probert.dasd.platform.machine')
@mock.patch('probert.dasd.dasdview')
def test_dasd_probe_dasdd(self, m_dasdview, m_machine):
m_machine.return_value = 's390x'
m_dasdview.side_effect = iter([self._load_test_data('dasdd.view')])
context = mock.MagicMock()
context.list_devices.side_effect = iter([
[{"MAJOR": "94", "DEVNAME": "/dev/dasdd", "ID_SERIAL": "0X1544",
"ID_PATH": "ccw-0.0.1544"}],
])
expected_results = {
'/dev/dasdd': update_probe_data(
expected_probe_data['/dev/dasdd'], device_id="0.0.1544")
}
self.assertEqual(expected_results, dasd.probe(context=context))
@mock.patch('probert.dasd.platform.machine')
@mock.patch('probert.dasd.dasdview')
def test_dasd_probe_dasde(self, m_dasdview, m_machine):
m_machine.return_value = 's390x'
m_dasdview.side_effect = iter([self._load_test_data('dasde.view')])
context = mock.MagicMock()
context.list_devices.side_effect = iter([
[{"MAJOR": "94", "DEVNAME": "/dev/dasde",
"ID_PATH": "ccw-0.0.2250"}],
])
expected_results = {
'/dev/dasde': update_probe_data(
expected_probe_data['/dev/dasde'], device_id="0.0.2250")
}
self.assertEqual(expected_results, dasd.probe(context=context))
@mock.patch('probert.dasd.platform.machine')
@mock.patch('probert.dasd.dasdview')
def test_dasd_probe_dasdd_skips_partitions(self, m_dasdview, m_machine):
m_machine.return_value = 's390x'
m_dasdview.side_effect = iter([self._load_test_data('dasdd.view')])
context = mock.MagicMock()
context.list_devices.side_effect = iter([
[{"MAJOR": "94", "DEVNAME": "/dev/dasdd", "ID_SERIAL": "0X1544",
"ID_PATH": "ccw-0.0.1544"}],
[{"MAJOR": "94", "DEVNAME": "/dev/dasdd1", "ID_SERIAL": "0X1544",
"ID_PATH": "ccw-0.0.1544", "PARTN": "1"}],
])
expected_results = {
'/dev/dasdd': update_probe_data(
expected_probe_data['/dev/dasdd'], device_id="0.0.1544"),
}
self.assertEqual(expected_results, dasd.probe(context=context))
@mock.patch('probert.dasd.subprocess.run')
@mock.patch('probert.dasd.open')
@mock.patch('probert.dasd.platform.machine')
def test_dasd_probe_virtio_dasd(self, m_machine, m_open, m_run):
m_machine.return_value = 's390x'
virtio_major = random_string()
devname = random_string()
m_open.return_value = ['{} virtblk\n'.format(virtio_major)]
m_run.return_value.returncode = 0
context = mock.MagicMock()
context.list_devices.side_effect = iter([
[{"MAJOR": virtio_major, "DEVNAME": devname}],
])
expected_results = {
devname: {'name': devname, 'type': 'virt'}
}
self.assertEqual(expected_results, dasd.probe(context=context))
m_run.assert_called_once_with(
['fdasd', '-i', devname],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
@mock.patch('probert.dasd.subprocess.run')
@mock.patch('probert.dasd.open')
@mock.patch('probert.dasd.platform.machine')
def test_dasd_probe_virtio_non_dasd(self, m_machine, m_open, m_run):
m_machine.return_value = 's390x'
virtio_major = random_string()
devname = random_string()
m_open.return_value = ['{} virtblk\n'.format(virtio_major)]
m_run.return_value.returncode = 1
context = mock.MagicMock()
context.list_devices.side_effect = iter([
[{"MAJOR": virtio_major, "DEVNAME": devname}],
])
self.assertEqual({}, dasd.probe(context=context))
m_run.assert_called_once_with(
['fdasd', '-i', devname],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)