tests: some more for qvm-template
QubesOS/qubes-issues#
This commit is contained in:
parent
f4e826e65d
commit
e00f35b9c3
@ -46,11 +46,12 @@ class TC_00_qvm_template(qubesadmin.tests.QubesTestCase):
|
|||||||
hdr = {
|
hdr = {
|
||||||
rpm.RPMTAG_SIGPGP: 'xxx', # non-empty
|
rpm.RPMTAG_SIGPGP: 'xxx', # non-empty
|
||||||
rpm.RPMTAG_SIGGPG: 'xxx', # non-empty
|
rpm.RPMTAG_SIGGPG: 'xxx', # non-empty
|
||||||
|
rpm.RPMTAG_NAME: 'qubes-template-test-vm',
|
||||||
}
|
}
|
||||||
mock_ts.return_value.hdrFromFdno.return_value = hdr
|
mock_ts.return_value.hdrFromFdno.return_value = hdr
|
||||||
mock_proc.return_value = b'dummy.rpm: digests signatures OK\n'
|
mock_proc.return_value = b'dummy.rpm: digests signatures OK\n'
|
||||||
ret = qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
ret = qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
||||||
['/path/to/key'])
|
'/path/to/key', template_name='test-vm')
|
||||||
mock_call.assert_called_once()
|
mock_call.assert_called_once()
|
||||||
mock_proc.assert_called_once()
|
mock_proc.assert_called_once()
|
||||||
self.assertEqual(hdr, ret)
|
self.assertEqual(hdr, ret)
|
||||||
@ -69,7 +70,7 @@ class TC_00_qvm_template(qubesadmin.tests.QubesTestCase):
|
|||||||
mock_proc.return_value = b'dummy.rpm: digests OK\n'
|
mock_proc.return_value = b'dummy.rpm: digests OK\n'
|
||||||
with self.assertRaises(Exception) as e:
|
with self.assertRaises(Exception) as e:
|
||||||
qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
||||||
['/path/to/key'])
|
'/path/to/key')
|
||||||
mock_call.assert_called_once()
|
mock_call.assert_called_once()
|
||||||
mock_proc.assert_called_once()
|
mock_proc.assert_called_once()
|
||||||
self.assertIn('Signature verification failed', e.exception.args[0])
|
self.assertIn('Signature verification failed', e.exception.args[0])
|
||||||
@ -88,7 +89,7 @@ class TC_00_qvm_template(qubesadmin.tests.QubesTestCase):
|
|||||||
mock_ts.return_value.hdrFromFdno.return_value = hdr
|
mock_ts.return_value.hdrFromFdno.return_value = hdr
|
||||||
mock_proc.return_value = b'dummy.rpm: digests OK\n'
|
mock_proc.return_value = b'dummy.rpm: digests OK\n'
|
||||||
ret = qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
ret = qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
||||||
['/path/to/key'], True)
|
'/path/to/key', True)
|
||||||
mock_proc.assert_not_called()
|
mock_proc.assert_not_called()
|
||||||
mock_call.assert_not_called()
|
mock_call.assert_not_called()
|
||||||
self.assertEqual(ret, hdr)
|
self.assertEqual(ret, hdr)
|
||||||
@ -102,7 +103,28 @@ class TC_00_qvm_template(qubesadmin.tests.QubesTestCase):
|
|||||||
['rpmkeys', '--checksig'], b'/dev/null: digests SIGNATURES NOT OK\n')
|
['rpmkeys', '--checksig'], b'/dev/null: digests SIGNATURES NOT OK\n')
|
||||||
with self.assertRaises(Exception) as e:
|
with self.assertRaises(Exception) as e:
|
||||||
qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
||||||
['/path/to/key'])
|
'/path/to/key')
|
||||||
|
mock_call.assert_called_once()
|
||||||
|
mock_proc.assert_called_once()
|
||||||
|
self.assertIn('Signature verification failed', e.exception.args[0])
|
||||||
|
mock_ts.assert_not_called()
|
||||||
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
@mock.patch('rpm.TransactionSet')
|
||||||
|
@mock.patch('subprocess.check_call')
|
||||||
|
@mock.patch('subprocess.check_output')
|
||||||
|
def test_004_verify_rpm_badname(self, mock_proc, mock_call, mock_ts):
|
||||||
|
mock_proc.side_effect = subprocess.CalledProcessError(1,
|
||||||
|
['rpmkeys', '--checksig'], b'/dev/null: digests signatures OK\n')
|
||||||
|
hdr = {
|
||||||
|
rpm.RPMTAG_SIGPGP: 'xxx', # non-empty
|
||||||
|
rpm.RPMTAG_SIGGPG: 'xxx', # non-empty
|
||||||
|
rpm.RPMTAG_NAME: 'qubes-template-unexpected',
|
||||||
|
}
|
||||||
|
mock_ts.return_value.hdrFromFdno.return_value = hdr
|
||||||
|
with self.assertRaises(Exception) as e:
|
||||||
|
qubesadmin.tools.qvm_template.verify_rpm('/dev/null',
|
||||||
|
'/path/to/key', template_name='test-vm')
|
||||||
mock_call.assert_called_once()
|
mock_call.assert_called_once()
|
||||||
mock_proc.assert_called_once()
|
mock_proc.assert_called_once()
|
||||||
self.assertIn('Signature verification failed', e.exception.args[0])
|
self.assertIn('Signature verification failed', e.exception.args[0])
|
||||||
@ -3677,7 +3699,7 @@ test-vm : Qubes template for fedora-31
|
|||||||
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
||||||
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
||||||
@mock.patch('qubesadmin.tools.qvm_template.qrexec_download')
|
@mock.patch('qubesadmin.tools.qvm_template.qrexec_download')
|
||||||
def test_189_download_verify_fail(self, mock_qrexec, mock_dllist,
|
def test_190_download_fail_verify(self, mock_qrexec, mock_dllist,
|
||||||
mock_verify_rpm):
|
mock_verify_rpm):
|
||||||
mock_qrexec.side_effect = self._mock_qrexec_download
|
mock_qrexec.side_effect = self._mock_qrexec_download
|
||||||
mock_verify_rpm.side_effect = \
|
mock_verify_rpm.side_effect = \
|
||||||
@ -3689,7 +3711,7 @@ test-vm : Qubes template for fedora-31
|
|||||||
repo_files=[],
|
repo_files=[],
|
||||||
keyring='/tmp/keyring.gpg',
|
keyring='/tmp/keyring.gpg',
|
||||||
releasever='4.1',
|
releasever='4.1',
|
||||||
nogpgcheck=False,
|
nogpgcheck=True, # make sure it gets ignored
|
||||||
downloaddir=dir
|
downloaddir=dir
|
||||||
)
|
)
|
||||||
with self.assertRaises(qubesadmin.tools.qvm_template.SignatureVerificationError):
|
with self.assertRaises(qubesadmin.tools.qvm_template.SignatureVerificationError):
|
||||||
@ -3705,7 +3727,168 @@ test-vm : Qubes template for fedora-31
|
|||||||
])
|
])
|
||||||
self.assertEqual(mock_dllist.mock_calls, [])
|
self.assertEqual(mock_dllist.mock_calls, [])
|
||||||
self.assertEqual(os.listdir(dir), [])
|
self.assertEqual(os.listdir(dir), [])
|
||||||
|
self.assertEqual(mock_verify_rpm.mock_calls, [
|
||||||
|
mock.call(re_str(dir + '/.*/qubes-template-fedora-31-1:2-3.rpm.UNTRUSTED'),
|
||||||
|
'/tmp/keyring.gpg', template_name='fedora-31'),
|
||||||
|
])
|
||||||
|
|
||||||
# TODO: test unexpected name downloaded
|
def _mock_qrexec_download_short(self, args, app, spec, path,
|
||||||
# TODO: test truncated download
|
dlsize=None, refresh=False):
|
||||||
# TODO: test no disk space
|
self.assertFalse(os.path.exists(path),
|
||||||
|
'{} should not exist before'.format(path))
|
||||||
|
# just create an empty file
|
||||||
|
with open(path, 'wb') as f:
|
||||||
|
if f is not None:
|
||||||
|
f.truncate(dlsize // 2)
|
||||||
|
|
||||||
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
||||||
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
||||||
|
@mock.patch('qubesadmin.tools.qvm_template.qrexec_download')
|
||||||
|
def test_191_download_fail_short(self, mock_qrexec, mock_dllist,
|
||||||
|
mock_verify_rpm):
|
||||||
|
mock_qrexec.side_effect = self._mock_qrexec_download_short
|
||||||
|
with tempfile.TemporaryDirectory() as dir, \
|
||||||
|
self.assertRaises(SystemExit):
|
||||||
|
args = argparse.Namespace(
|
||||||
|
repo_files=[],
|
||||||
|
keyring='/tmp/keyring.gpg',
|
||||||
|
releasever='4.1',
|
||||||
|
nogpgcheck=False,
|
||||||
|
retries=1
|
||||||
|
)
|
||||||
|
qubesadmin.tools.qvm_template.download(args, self.app, dir, {
|
||||||
|
'fedora-31': qubesadmin.tools.qvm_template.DlEntry(
|
||||||
|
('1', '2', '3'), 'qubes-templates-itl', 1048576),
|
||||||
|
})
|
||||||
|
self.assertEqual(mock_qrexec.mock_calls, [
|
||||||
|
mock.call(args, self.app, 'qubes-template-fedora-31-1:2-3',
|
||||||
|
re_str(dir + '/.*/qubes-template-fedora-31-1:2-3.rpm.UNTRUSTED'),
|
||||||
|
1048576),
|
||||||
|
])
|
||||||
|
self.assertEqual(mock_dllist.mock_calls, [])
|
||||||
|
self.assertEqual(mock_verify_rpm.mock_calls, [])
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch('os.rename')
|
||||||
|
@mock.patch('os.makedirs')
|
||||||
|
@mock.patch('subprocess.check_call')
|
||||||
|
@mock.patch('qubesadmin.tools.qvm_template.confirm_action')
|
||||||
|
@mock.patch('qubesadmin.tools.qvm_template.extract_rpm')
|
||||||
|
@mock.patch('qubesadmin.tools.qvm_template.download')
|
||||||
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
||||||
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
||||||
|
def test_200_reinstall_success(
|
||||||
|
self,
|
||||||
|
mock_verify,
|
||||||
|
mock_dl_list,
|
||||||
|
mock_dl,
|
||||||
|
mock_extract,
|
||||||
|
mock_confirm,
|
||||||
|
mock_call,
|
||||||
|
mock_mkdirs,
|
||||||
|
mock_rename):
|
||||||
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
|
||||||
|
b'0\x00test-vm class=TemplateVM state=Halted\n'
|
||||||
|
build_time = '2020-09-01 14:30:00' # 1598970600
|
||||||
|
install_time = '2020-09-01 15:30:00'
|
||||||
|
for key, val in [
|
||||||
|
('name', 'test-vm'),
|
||||||
|
('epoch', '2'),
|
||||||
|
('version', '4.1'),
|
||||||
|
('release', '2020')]:
|
||||||
|
self.app.expected_calls[(
|
||||||
|
'test-vm',
|
||||||
|
'admin.vm.feature.Get',
|
||||||
|
f'template-{key}',
|
||||||
|
None)] = b'0\0' + val.encode()
|
||||||
|
for key, val in [
|
||||||
|
('name', 'test-vm'),
|
||||||
|
('epoch', '2'),
|
||||||
|
('version', '4.1'),
|
||||||
|
('release', '2020'),
|
||||||
|
('reponame', 'qubes-templates-itl'),
|
||||||
|
('buildtime', build_time),
|
||||||
|
('installtime', install_time),
|
||||||
|
('license', 'GPL'),
|
||||||
|
('url', 'https://qubes-os.org'),
|
||||||
|
('summary', 'Summary'),
|
||||||
|
('description', 'Desc|desc')]:
|
||||||
|
self.app.expected_calls[(
|
||||||
|
'test-vm',
|
||||||
|
'admin.vm.feature.Set',
|
||||||
|
f'template-{key}',
|
||||||
|
val.encode())] = b'0\0'
|
||||||
|
rpm_hdr = {
|
||||||
|
rpm.RPMTAG_NAME : 'qubes-template-test-vm',
|
||||||
|
rpm.RPMTAG_BUILDTIME : 1598970600,
|
||||||
|
rpm.RPMTAG_DESCRIPTION : 'Desc\ndesc',
|
||||||
|
rpm.RPMTAG_EPOCHNUM : 2,
|
||||||
|
rpm.RPMTAG_LICENSE : 'GPL',
|
||||||
|
rpm.RPMTAG_RELEASE : '2020',
|
||||||
|
rpm.RPMTAG_SUMMARY : 'Summary',
|
||||||
|
rpm.RPMTAG_URL : 'https://qubes-os.org',
|
||||||
|
rpm.RPMTAG_VERSION : '4.1'
|
||||||
|
}
|
||||||
|
mock_dl.return_value = {'test-vm': rpm_hdr}
|
||||||
|
dl_list = {
|
||||||
|
'test-vm': qubesadmin.tools.qvm_template.DlEntry(
|
||||||
|
('1', '4.1', '20200101'), 'qubes-templates-itl', 1048576)
|
||||||
|
}
|
||||||
|
mock_dl_list.return_value = dl_list
|
||||||
|
mock_call.side_effect = self.add_new_vm_side_effect
|
||||||
|
mock_time = mock.Mock(wraps=datetime.datetime)
|
||||||
|
mock_time.now.return_value = \
|
||||||
|
datetime.datetime(2020, 9, 1, 15, 30, tzinfo=datetime.timezone.utc)
|
||||||
|
selector = qubesadmin.tools.qvm_template.VersionSelector.REINSTALL
|
||||||
|
with mock.patch('qubesadmin.tools.qvm_template.LOCK_FILE', '/tmp/test.lock'), \
|
||||||
|
mock.patch('datetime.datetime', new=mock_time), \
|
||||||
|
mock.patch('tempfile.TemporaryDirectory') as mock_tmpdir:
|
||||||
|
args = argparse.Namespace(
|
||||||
|
templates=['test-vm'],
|
||||||
|
keyring='/tmp/keyring.gpg',
|
||||||
|
nogpgcheck=False,
|
||||||
|
cachedir='/var/cache/qvm-template',
|
||||||
|
repo_files=[],
|
||||||
|
releasever='4.1',
|
||||||
|
yes=False,
|
||||||
|
keep_cache=True,
|
||||||
|
allow_pv=False,
|
||||||
|
pool=None
|
||||||
|
)
|
||||||
|
mock_tmpdir.return_value.__enter__.return_value = \
|
||||||
|
'/var/tmp/qvm-template-tmpdir'
|
||||||
|
qubesadmin.tools.qvm_template.install(args, self.app,
|
||||||
|
version_selector=selector,
|
||||||
|
override_existing=True)
|
||||||
|
# Attempt to get download list
|
||||||
|
self.assertEqual(mock_dl_list.mock_calls, [
|
||||||
|
mock.call(args, self.app, version_selector=selector)
|
||||||
|
])
|
||||||
|
mock_dl.assert_called_with(args, self.app,
|
||||||
|
dl_list=dl_list, version_selector=selector)
|
||||||
|
# already verified by download()
|
||||||
|
self.assertEqual(mock_verify.mock_calls, [])
|
||||||
|
# Package is extracted
|
||||||
|
mock_extract.assert_called_with('test-vm',
|
||||||
|
'/var/cache/qvm-template/qubes-template-test-vm-1:4.1-20200101.rpm',
|
||||||
|
'/var/tmp/qvm-template-tmpdir')
|
||||||
|
# Expect override confirmation
|
||||||
|
self.assertEqual(mock_confirm.mock_calls,
|
||||||
|
[mock.call(re_str(r'.*override changes.*:'), ['test-vm'])])
|
||||||
|
# qvm-template-postprocess is called
|
||||||
|
self.assertEqual(mock_call.mock_calls, [
|
||||||
|
mock.call([
|
||||||
|
'qvm-template-postprocess',
|
||||||
|
'--really',
|
||||||
|
'--no-installed-by-rpm',
|
||||||
|
'post-install',
|
||||||
|
'test-vm',
|
||||||
|
'/var/tmp/qvm-template-tmpdir'
|
||||||
|
'/var/lib/qubes/vm-templates/test-vm'
|
||||||
|
])
|
||||||
|
])
|
||||||
|
# Cache directory created
|
||||||
|
self.assertEqual(mock_mkdirs.mock_calls, [
|
||||||
|
mock.call(args.cachedir, exist_ok=True)
|
||||||
|
])
|
||||||
|
self.assertAllCalled()
|
Loading…
Reference in New Issue
Block a user