2020-09-03 19:56:15 +02:00
from unittest import mock
import argparse
import asyncio
import datetime
import io
import os
import pathlib
import subprocess
import tempfile
import rpm
import qubesadmin . tests
import qubesadmin . tools . qvm_template
class TC_00_qvm_template ( qubesadmin . tests . QubesTestCase ) :
def setUp ( self ) :
super ( ) . setUp ( )
def tearDown ( self ) :
super ( ) . tearDown ( )
def test_000_verify_rpm_success ( self ) :
ts = mock . MagicMock ( )
# Just return a dict instead of rpm.hdr
hdr = {
rpm . RPMTAG_SIGPGP : ' xxx ' , # non-empty
rpm . RPMTAG_SIGGPG : ' xxx ' , # non-empty
}
ts . hdrFromFdno . return_value = hdr
ret = qubesadmin . tools . qvm_template . verify_rpm ( ' /dev/null ' , ts )
ts . hdrFromFdno . assert_called_once ( )
self . assertEqual ( hdr , ret )
self . assertAllCalled ( )
def test_001_verify_rpm_nosig_fail ( self ) :
ts = mock . MagicMock ( )
# Just return a dict instead of rpm.hdr
hdr = {
rpm . RPMTAG_SIGPGP : None , # empty
rpm . RPMTAG_SIGGPG : None , # empty
}
ts . hdrFromFdno . return_value = hdr
ret = qubesadmin . tools . qvm_template . verify_rpm ( ' /dev/null ' , ts )
ts . hdrFromFdno . assert_called_once ( )
self . assertEqual ( ret , None )
self . assertAllCalled ( )
def test_002_verify_rpm_nosig_success ( self ) :
ts = mock . MagicMock ( )
# Just return a dict instead of rpm.hdr
hdr = {
rpm . RPMTAG_SIGPGP : None , # empty
rpm . RPMTAG_SIGGPG : None , # empty
}
ts . hdrFromFdno . return_value = hdr
ret = qubesadmin . tools . qvm_template . verify_rpm ( ' /dev/null ' , ts , True )
ts . hdrFromFdno . assert_called_once ( )
self . assertEqual ( ret , hdr )
self . assertAllCalled ( )
def test_003_verify_rpm_badsig_fail ( self ) :
ts = mock . MagicMock ( )
def f ( * args ) :
raise rpm . error ( ' public key not trusted ' )
ts . hdrFromFdno . side_effect = f
ret = qubesadmin . tools . qvm_template . verify_rpm ( ' /dev/null ' , ts )
ts . hdrFromFdno . assert_called_once ( )
self . assertEqual ( ret , None )
self . assertAllCalled ( )
@mock.patch ( ' subprocess.Popen ' )
def test_010_extract_rpm_success ( self , mock_popen ) :
pipe = mock . Mock ( )
mock_popen . return_value . stdout = pipe
mock_popen . return_value . wait . return_value = 0
with tempfile . NamedTemporaryFile ( ) as fd , \
tempfile . TemporaryDirectory ( ) as dir :
path = fd . name
dirpath = dir
ret = qubesadmin . tools . qvm_template . extract_rpm (
' test-vm ' , path , dirpath )
self . assertEqual ( ret , True )
self . assertEqual ( mock_popen . mock_calls , [
mock . call ( [ ' rpm2cpio ' , path ] , stdout = subprocess . PIPE ) ,
mock . call ( [
' cpio ' ,
' -idm ' ,
' -D ' ,
dirpath ,
' ./var/lib/qubes/vm-templates/test-vm/* '
] , stdin = pipe , stdout = subprocess . DEVNULL ) ,
mock . call ( ) . wait ( ) ,
mock . call ( ) . wait ( )
] )
self . assertAllCalled ( )
@mock.patch ( ' subprocess.Popen ' )
def test_011_extract_rpm_fail ( self , mock_popen ) :
pipe = mock . Mock ( )
mock_popen . return_value . stdout = pipe
mock_popen . return_value . wait . return_value = 1
with tempfile . NamedTemporaryFile ( ) as fd , \
tempfile . TemporaryDirectory ( ) as dir :
path = fd . name
dirpath = dir
ret = qubesadmin . tools . qvm_template . extract_rpm (
' test-vm ' , path , dirpath )
self . assertEqual ( ret , False )
self . assertEqual ( mock_popen . mock_calls , [
mock . call ( [ ' rpm2cpio ' , path ] , stdout = subprocess . PIPE ) ,
mock . call ( [
' cpio ' ,
' -idm ' ,
' -D ' ,
dirpath ,
' ./var/lib/qubes/vm-templates/test-vm/* '
] , stdin = pipe , stdout = subprocess . DEVNULL ) ,
mock . call ( ) . wait ( )
] )
self . assertAllCalled ( )
def add_new_vm_side_effect ( self , * args , * * kwargs ) :
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = \
b ' 0 \0 test-vm class=TemplateVM state=Halted \n '
self . app . domains . clear_cache ( )
return self . app . domains [ ' test-vm ' ]
@mock.patch ( ' os.remove ' )
@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 ' )
@mock.patch ( ' qubesadmin.tools.qvm_template.rpm_transactionset ' )
def test_100_install_local_success (
self ,
mock_ts ,
mock_verify ,
mock_dl_list ,
mock_dl ,
mock_extract ,
mock_confirm ,
mock_call ,
mock_mkdirs ,
mock_rename ,
mock_remove ) :
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = b ' 0 \0 '
2020-09-06 17:57:42 +02:00
build_time = ' 2020-09-01 14:30:00 ' # 1598970600
install_time = ' 2020-09-01 15:30:00 '
2020-09-03 19:56:15 +02:00
for key , val in [
( ' name ' , ' test-vm ' ) ,
( ' epoch ' , ' 2 ' ) ,
( ' version ' , ' 4.1 ' ) ,
( ' release ' , ' 2020 ' ) ,
( ' reponame ' , ' @commandline ' ) ,
( ' 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 '
mock_verify . return_value = {
rpm . RPMTAG_NAME : ' qubes-template-test-vm ' ,
rpm . RPMTAG_BUILDTIME : 1598970600 ,
rpm . RPMTAG_DESCRIPTION : ' Desc \n desc ' ,
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_list . return_value = { }
mock_call . side_effect = self . add_new_vm_side_effect
mock_time = mock . Mock ( wraps = datetime . datetime )
mock_time . today . return_value = \
datetime . datetime . fromisoformat ( install_time )
with mock . patch ( ' builtins.open ' , mock . mock_open ( ) ) as mock_open , \
mock . patch ( ' datetime.datetime ' , new = mock_time ) , \
mock . patch ( ' tempfile.TemporaryDirectory ' ) as mock_tmpdir , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err , \
tempfile . NamedTemporaryFile ( suffix = ' .rpm ' ) as template_file :
path = template_file . name
args = argparse . Namespace (
templates = [ path ] ,
keyring = ' /usr/share/qubes/repo-templates/keys ' ,
nogpgcheck = False ,
cachedir = ' /var/cache/qvm-template ' ,
yes = False ,
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 )
# Lock file created
self . assertEqual ( mock_open . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' , ' x ' ) ,
mock . call ( ) . __enter__ ( ) ,
mock . call ( ) . __exit__ ( None , None , None )
] )
# Keyring created
self . assertEqual ( mock_ts . mock_calls , [
mock . call ( ' /usr/share/qubes/repo-templates/keys ' )
] )
# Package verified
self . assertEqual ( mock_verify . mock_calls , [
mock . call ( path , mock_ts ( ' /usr/share/qubes/repo-templates/keys ' ) ,
False )
] )
# Attempt to get download list
selector = qubesadmin . tools . qvm_template . VersionSelector . LATEST
self . assertEqual ( mock_dl_list . mock_calls , [
mock . call ( args , self . app , version_selector = selector )
] )
# Nothing downloaded
self . assertEqual ( mock_dl . mock_calls , [
mock . call ( args , self . app , path_override = ' /var/cache/qvm-template ' ,
dl_list = { } , suffix = ' .unverified ' , version_selector = selector )
] )
# Package is extracted
self . assertEqual ( mock_extract . mock_calls , [
mock . call ( ' test-vm ' , path , ' /var/tmp/qvm-template-tmpdir ' )
] )
# No packages overwritten, so no confirm needed
self . assertEqual ( mock_confirm . mock_calls , [ ] )
# 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 )
] )
# No templates downloaded, thus no renames needed
self . assertEqual ( mock_rename . mock_calls , [ ] )
# Lock file removed
self . assertEqual ( mock_remove . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' )
] )
self . assertAllCalled ( )
@mock.patch ( ' os.remove ' )
@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 ' )
@mock.patch ( ' qubesadmin.tools.qvm_template.rpm_transactionset ' )
def test_101_install_local_postprocargs_success (
self ,
mock_ts ,
mock_verify ,
mock_dl_list ,
mock_dl ,
mock_extract ,
mock_confirm ,
mock_call ,
mock_mkdirs ,
mock_rename ,
mock_remove ) :
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = b ' 0 \0 '
2020-09-06 17:57:42 +02:00
build_time = ' 2020-09-01 14:30:00 ' # 1598970600
install_time = ' 2020-09-01 15:30:00 '
2020-09-03 19:56:15 +02:00
for key , val in [
( ' name ' , ' test-vm ' ) ,
( ' epoch ' , ' 2 ' ) ,
( ' version ' , ' 4.1 ' ) ,
( ' release ' , ' 2020 ' ) ,
( ' reponame ' , ' @commandline ' ) ,
( ' 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 '
mock_verify . return_value = {
rpm . RPMTAG_NAME : ' qubes-template-test-vm ' ,
rpm . RPMTAG_BUILDTIME : 1598970600 ,
rpm . RPMTAG_DESCRIPTION : ' Desc \n desc ' ,
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_list . return_value = { }
mock_call . side_effect = self . add_new_vm_side_effect
mock_time = mock . Mock ( wraps = datetime . datetime )
mock_time . today . return_value = \
datetime . datetime . fromisoformat ( install_time )
with mock . patch ( ' builtins.open ' , mock . mock_open ( ) ) as mock_open , \
mock . patch ( ' datetime.datetime ' , new = mock_time ) , \
mock . patch ( ' tempfile.TemporaryDirectory ' ) as mock_tmpdir , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err , \
tempfile . NamedTemporaryFile ( suffix = ' .rpm ' ) as template_file :
path = template_file . name
args = argparse . Namespace (
templates = [ path ] ,
keyring = ' /usr/share/qubes/repo-templates/keys ' ,
nogpgcheck = False ,
cachedir = ' /var/cache/qvm-template ' ,
yes = False ,
allow_pv = True ,
pool = ' my-pool '
)
mock_tmpdir . return_value . __enter__ . return_value = \
' /var/tmp/qvm-template-tmpdir '
qubesadmin . tools . qvm_template . install ( args , self . app )
# Lock file created
self . assertEqual ( mock_open . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' , ' x ' ) ,
mock . call ( ) . __enter__ ( ) ,
mock . call ( ) . __exit__ ( None , None , None )
] )
# Keyring created
self . assertEqual ( mock_ts . mock_calls , [
mock . call ( ' /usr/share/qubes/repo-templates/keys ' )
] )
# Package verified
self . assertEqual ( mock_verify . mock_calls , [
mock . call ( path , mock_ts ( ' /usr/share/qubes/repo-templates/keys ' ) ,
False )
] )
# Attempt to get download list
selector = qubesadmin . tools . qvm_template . VersionSelector . LATEST
self . assertEqual ( mock_dl_list . mock_calls , [
mock . call ( args , self . app , version_selector = selector )
] )
# Nothing downloaded
self . assertEqual ( mock_dl . mock_calls , [
mock . call ( args , self . app , path_override = ' /var/cache/qvm-template ' ,
dl_list = { } , suffix = ' .unverified ' , version_selector = selector )
] )
# Package is extracted
self . assertEqual ( mock_extract . mock_calls , [
mock . call ( ' test-vm ' , path , ' /var/tmp/qvm-template-tmpdir ' )
] )
# No packages overwritten, so no confirm needed
self . assertEqual ( mock_confirm . mock_calls , [ ] )
# qvm-template-postprocess is called
self . assertEqual ( mock_call . mock_calls , [
mock . call ( [
' qvm-template-postprocess ' ,
' --really ' ,
' --no-installed-by-rpm ' ,
' --allow-pv ' ,
' --pool ' ,
' my-pool ' ,
' 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 )
] )
# No templates downloaded, thus no renames needed
self . assertEqual ( mock_rename . mock_calls , [ ] )
# Lock file removed
self . assertEqual ( mock_remove . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' )
] )
self . assertAllCalled ( )
@mock.patch ( ' os.remove ' )
@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 ' )
@mock.patch ( ' qubesadmin.tools.qvm_template.rpm_transactionset ' )
def test_102_install_local_badsig_fail (
self ,
mock_ts ,
mock_verify ,
mock_dl_list ,
mock_dl ,
mock_extract ,
mock_confirm ,
mock_call ,
mock_mkdirs ,
mock_rename ,
mock_remove ) :
mock_verify . return_value = None
mock_time = mock . Mock ( wraps = datetime . datetime )
with mock . patch ( ' builtins.open ' , mock . mock_open ( ) ) as mock_open , \
mock . patch ( ' datetime.datetime ' , new = mock_time ) , \
mock . patch ( ' tempfile.TemporaryDirectory ' ) as mock_tmpdir , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err , \
tempfile . NamedTemporaryFile ( suffix = ' .rpm ' ) as template_file :
path = template_file . name
args = argparse . Namespace (
templates = [ path ] ,
keyring = ' /usr/share/qubes/repo-templates/keys ' ,
nogpgcheck = False ,
cachedir = ' /var/cache/qvm-template ' ,
yes = False ,
allow_pv = False ,
pool = None
)
mock_tmpdir . return_value . __enter__ . return_value = \
' /var/tmp/qvm-template-tmpdir '
# Should raise parser.error
with self . assertRaises ( SystemExit ) :
qubesadmin . tools . qvm_template . install ( args , self . app )
# Lock file created
self . assertEqual ( mock_open . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' , ' x ' ) ,
mock . call ( ) . __enter__ ( ) ,
mock . call ( ) . __exit__ ( None , None , None )
] )
# Check error message
self . assertTrue ( ' verification failed ' in mock_err . getvalue ( ) )
# Keyring created
self . assertEqual ( mock_ts . mock_calls , [
mock . call ( ' /usr/share/qubes/repo-templates/keys ' )
] )
# Package verified
self . assertEqual ( mock_verify . mock_calls , [
mock . call ( path , mock_ts ( ' /usr/share/qubes/repo-templates/keys ' ) ,
False )
] )
# Should not be executed:
self . assertEqual ( mock_dl_list . mock_calls , [ ] )
self . assertEqual ( mock_dl . mock_calls , [ ] )
self . assertEqual ( mock_extract . mock_calls , [ ] )
self . assertEqual ( mock_confirm . mock_calls , [ ] )
self . assertEqual ( mock_call . mock_calls , [ ] )
self . assertEqual ( mock_rename . mock_calls , [ ] )
# Lock file removed
self . assertEqual ( mock_remove . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' )
] )
self . assertAllCalled ( )
@mock.patch ( ' os.remove ' )
@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 ' )
@mock.patch ( ' qubesadmin.tools.qvm_template.rpm_transactionset ' )
def test_103_install_local_exists_fail (
self ,
mock_ts ,
mock_verify ,
mock_dl_list ,
mock_dl ,
mock_extract ,
mock_confirm ,
mock_call ,
mock_mkdirs ,
mock_rename ,
mock_remove ) :
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = \
b ' 0 \0 test-vm class=TemplateVM state=Halted \n '
mock_verify . return_value = {
rpm . RPMTAG_NAME : ' qubes-template-test-vm ' ,
rpm . RPMTAG_BUILDTIME : 1598970600 ,
rpm . RPMTAG_DESCRIPTION : ' Desc \n desc ' ,
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_list . return_value = { }
mock_time = mock . Mock ( wraps = datetime . datetime )
with mock . patch ( ' builtins.open ' , mock . mock_open ( ) ) as mock_open , \
mock . patch ( ' datetime.datetime ' , new = mock_time ) , \
mock . patch ( ' tempfile.TemporaryDirectory ' ) as mock_tmpdir , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err , \
tempfile . NamedTemporaryFile ( suffix = ' .rpm ' ) as template_file :
path = template_file . name
args = argparse . Namespace (
templates = [ path ] ,
keyring = ' /usr/share/qubes/repo-templates/keys ' ,
nogpgcheck = False ,
cachedir = ' /var/cache/qvm-template ' ,
yes = False ,
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 )
# Lock file created
self . assertEqual ( mock_open . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' , ' x ' ) ,
mock . call ( ) . __enter__ ( ) ,
mock . call ( ) . __exit__ ( None , None , None )
] )
# Check warning message
self . assertTrue ( ' already installed ' in mock_err . getvalue ( ) )
# Keyring created
self . assertEqual ( mock_ts . mock_calls , [
mock . call ( ' /usr/share/qubes/repo-templates/keys ' )
] )
# Package verified
self . assertEqual ( mock_verify . mock_calls , [
mock . call ( path , mock_ts ( ' /usr/share/qubes/repo-templates/keys ' ) ,
False )
] )
# Attempt to get download list
selector = qubesadmin . tools . qvm_template . VersionSelector . LATEST
self . assertEqual ( mock_dl_list . mock_calls , [
mock . call ( args , self . app , version_selector = selector )
] )
# Nothing downloaded
self . assertEqual ( mock_dl . mock_calls , [
mock . call ( args , self . app , path_override = ' /var/cache/qvm-template ' ,
dl_list = { } , suffix = ' .unverified ' , version_selector = selector )
] )
# Should not be executed:
self . assertEqual ( mock_extract . mock_calls , [ ] )
self . assertEqual ( mock_confirm . mock_calls , [ ] )
self . assertEqual ( mock_call . mock_calls , [ ] )
self . assertEqual ( mock_rename . mock_calls , [ ] )
# Lock file removed
self . assertEqual ( mock_remove . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' )
] )
self . assertAllCalled ( )
@mock.patch ( ' os.remove ' )
@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 ' )
@mock.patch ( ' qubesadmin.tools.qvm_template.rpm_transactionset ' )
def test_104_install_local_badpkgname_fail (
self ,
mock_ts ,
mock_verify ,
mock_dl_list ,
mock_dl ,
mock_extract ,
mock_confirm ,
mock_call ,
mock_mkdirs ,
mock_rename ,
mock_remove ) :
mock_verify . return_value = {
rpm . RPMTAG_NAME : ' Xqubes-template-test-vm ' ,
rpm . RPMTAG_BUILDTIME : 1598970600 ,
rpm . RPMTAG_DESCRIPTION : ' Desc \n desc ' ,
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_time = mock . Mock ( wraps = datetime . datetime )
with mock . patch ( ' builtins.open ' , mock . mock_open ( ) ) as mock_open , \
mock . patch ( ' datetime.datetime ' , new = mock_time ) , \
mock . patch ( ' tempfile.TemporaryDirectory ' ) as mock_tmpdir , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err , \
tempfile . NamedTemporaryFile ( suffix = ' .rpm ' ) as template_file :
path = template_file . name
args = argparse . Namespace (
templates = [ path ] ,
keyring = ' /usr/share/qubes/repo-templates/keys ' ,
nogpgcheck = False ,
cachedir = ' /var/cache/qvm-template ' ,
yes = False ,
allow_pv = False ,
pool = None
)
mock_tmpdir . return_value . __enter__ . return_value = \
' /var/tmp/qvm-template-tmpdir '
with self . assertRaises ( SystemExit ) :
qubesadmin . tools . qvm_template . install ( args , self . app )
# Lock file created
self . assertEqual ( mock_open . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' , ' x ' ) ,
mock . call ( ) . __enter__ ( ) ,
mock . call ( ) . __exit__ ( None , None , None )
] )
# Check error message
self . assertTrue ( ' Illegal package name ' in mock_err . getvalue ( ) )
# Keyring created
self . assertEqual ( mock_ts . mock_calls , [
mock . call ( ' /usr/share/qubes/repo-templates/keys ' )
] )
# Package verified
self . assertEqual ( mock_verify . mock_calls , [
mock . call ( path , mock_ts ( ' /usr/share/qubes/repo-templates/keys ' ) ,
False )
] )
# Should not be executed:
self . assertEqual ( mock_dl_list . mock_calls , [ ] )
self . assertEqual ( mock_dl . mock_calls , [ ] )
self . assertEqual ( mock_extract . mock_calls , [ ] )
self . assertEqual ( mock_confirm . mock_calls , [ ] )
self . assertEqual ( mock_call . mock_calls , [ ] )
self . assertEqual ( mock_rename . mock_calls , [ ] )
# Lock file removed
self . assertEqual ( mock_remove . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' )
] )
self . assertAllCalled ( )
@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 ' )
@mock.patch ( ' qubesadmin.tools.qvm_template.rpm_transactionset ' )
def test_105_install_local_existinginstance_fail (
self ,
mock_ts ,
mock_verify ,
mock_dl_list ,
mock_dl ,
mock_extract ,
mock_confirm ,
mock_call ,
mock_mkdirs ,
mock_rename ) :
mock_time = mock . Mock ( wraps = datetime . datetime )
with mock . patch ( ' datetime.datetime ' , new = mock_time ) , \
mock . patch ( ' tempfile.TemporaryDirectory ' ) as mock_tmpdir , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err , \
tempfile . NamedTemporaryFile ( suffix = ' .rpm ' ) as template_file :
path = template_file . name
args = argparse . Namespace (
templates = [ path ] ,
keyring = ' /usr/share/qubes/repo-templates/keys ' ,
nogpgcheck = False ,
cachedir = ' /var/cache/qvm-template ' ,
yes = False ,
allow_pv = False ,
pool = None
)
mock_tmpdir . return_value . __enter__ . return_value = \
' /var/tmp/qvm-template-tmpdir '
pathlib . Path ( ' /var/tmp/qvm-template.lck ' ) . touch ( )
try :
with self . assertRaises ( SystemExit ) , \
mock . patch ( ' os.remove ' ) as mock_remove :
qubesadmin . tools . qvm_template . install ( args , self . app )
self . assertEqual ( mock_remove . mock_calls , [ ] )
finally :
# Lock file not removed
self . assertTrue ( os . path . exists ( ' /var/tmp/qvm-template.lck ' ) )
os . remove ( ' /var/tmp/qvm-template.lck ' )
# Check error message
self . assertTrue ( ' another instance of qvm-template is running ' \
in mock_err . getvalue ( ) )
# Should not be executed:
self . assertEqual ( mock_ts . mock_calls , [ ] )
self . assertEqual ( mock_verify . mock_calls , [ ] )
self . assertEqual ( mock_dl_list . mock_calls , [ ] )
self . assertEqual ( mock_dl . mock_calls , [ ] )
self . assertEqual ( mock_extract . mock_calls , [ ] )
self . assertEqual ( mock_confirm . mock_calls , [ ] )
self . assertEqual ( mock_call . mock_calls , [ ] )
self . assertEqual ( mock_rename . mock_calls , [ ] )
self . assertAllCalled ( )
@mock.patch ( ' os.remove ' )
@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 ' )
@mock.patch ( ' qubesadmin.tools.qvm_template.rpm_transactionset ' )
def test_106_install_local_badpath_fail (
self ,
mock_ts ,
mock_verify ,
mock_dl_list ,
mock_dl ,
mock_extract ,
mock_confirm ,
mock_call ,
mock_mkdirs ,
mock_rename ,
mock_remove ) :
mock_time = mock . Mock ( wraps = datetime . datetime )
with mock . patch ( ' builtins.open ' , mock . mock_open ( ) ) as mock_open , \
mock . patch ( ' datetime.datetime ' , new = mock_time ) , \
mock . patch ( ' tempfile.TemporaryDirectory ' ) as mock_tmpdir , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err :
path = ' /var/tmp/ShOulD-NoT-ExIsT.rpm '
args = argparse . Namespace (
templates = [ path ] ,
keyring = ' /usr/share/qubes/repo-templates/keys ' ,
nogpgcheck = False ,
cachedir = ' /var/cache/qvm-template ' ,
yes = False ,
allow_pv = False ,
pool = None
)
mock_tmpdir . return_value . __enter__ . return_value = \
' /var/tmp/qvm-template-tmpdir '
with self . assertRaises ( SystemExit ) :
qubesadmin . tools . qvm_template . install ( args , self . app )
# Lock file created
self . assertEqual ( mock_open . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' , ' x ' ) ,
mock . call ( ) . __enter__ ( ) ,
mock . call ( ) . __exit__ ( None , None , None )
] )
# Check error message
self . assertTrue ( f " RPM file ' { path } ' not found " \
in mock_err . getvalue ( ) )
# Keyring created
self . assertEqual ( mock_ts . mock_calls , [
mock . call ( ' /usr/share/qubes/repo-templates/keys ' )
] )
# Should not be executed:
self . assertEqual ( mock_verify . mock_calls , [ ] )
self . assertEqual ( mock_dl_list . mock_calls , [ ] )
self . assertEqual ( mock_dl . mock_calls , [ ] )
self . assertEqual ( mock_extract . mock_calls , [ ] )
self . assertEqual ( mock_confirm . mock_calls , [ ] )
self . assertEqual ( mock_call . mock_calls , [ ] )
self . assertEqual ( mock_rename . mock_calls , [ ] )
# Lock file removed
self . assertEqual ( mock_remove . mock_calls , [
mock . call ( ' /var/tmp/qvm-template.lck ' )
] )
self . assertAllCalled ( )
2020-09-06 18:41:03 +02:00
def test_110_qrexec_payload_refresh_success ( self ) :
with tempfile . NamedTemporaryFile ( ) as repo_conf1 , \
tempfile . NamedTemporaryFile ( ) as repo_conf2 :
repo_str1 = \
''' [qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl / repodata / repomd . xml . metalink
enabled = 1
fastestmirror = 1
metadata_expire = 7 d
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_str2 = \
''' [qubes-templates-itl-testing]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl-testing
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl-testing
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl - testing / repodata / repomd . xml . metalink
enabled = 0
fastestmirror = 1
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_conf1 . write ( repo_str1 . encode ( ) )
repo_conf1 . flush ( )
repo_conf2 . write ( repo_str2 . encode ( ) )
repo_conf2 . flush ( )
args = argparse . Namespace (
enablerepo = [ ' repo1 ' , ' repo2 ' ] ,
disablerepo = [ ' repo3 ' , ' repo4 ' , ' repo5 ' ] ,
repoid = [ ] ,
releasever = ' 4.1 ' ,
repo_files = [ repo_conf1 . name , repo_conf2 . name ]
)
res = qubesadmin . tools . qvm_template . qrexec_payload ( args , self . app ,
' qubes-template-fedora-32 ' , True )
self . assertEqual ( res ,
''' --enablerepo=repo1
- - enablerepo = repo2
- - disablerepo = repo3
- - disablerepo = repo4
- - disablerepo = repo5
- - refresh
- - releasever = 4.1
qubes - template - fedora - 32
- - -
''' + repo_str1 + ' \n ' + repo_str2 + ' \n ' )
self . assertAllCalled ( )
def test_111_qrexec_payload_norefresh_success ( self ) :
with tempfile . NamedTemporaryFile ( ) as repo_conf1 :
repo_str1 = \
''' [qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl / repodata / repomd . xml . metalink
enabled = 1
fastestmirror = 1
metadata_expire = 7 d
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_conf1 . write ( repo_str1 . encode ( ) )
repo_conf1 . flush ( )
args = argparse . Namespace (
enablerepo = [ ] ,
disablerepo = [ ] ,
repoid = [ ' repo1 ' , ' repo2 ' ] ,
releasever = ' 4.1 ' ,
repo_files = [ repo_conf1 . name ]
)
res = qubesadmin . tools . qvm_template . qrexec_payload ( args , self . app ,
' qubes-template-fedora-32 ' , False )
self . assertEqual ( res ,
''' --repoid=repo1
- - repoid = repo2
- - releasever = 4.1
qubes - template - fedora - 32
- - -
''' + repo_str1 + ' \n ' )
self . assertAllCalled ( )
def test_112_qrexec_payload_specnewline_fail ( self ) :
with tempfile . NamedTemporaryFile ( ) as repo_conf1 :
repo_str1 = \
''' [qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl / repodata / repomd . xml . metalink
enabled = 1
fastestmirror = 1
metadata_expire = 7 d
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_conf1 . write ( repo_str1 . encode ( ) )
repo_conf1 . flush ( )
args = argparse . Namespace (
enablerepo = [ ] ,
disablerepo = [ ] ,
repoid = [ ' repo1 ' , ' repo2 ' ] ,
releasever = ' 4.1 ' ,
repo_files = [ repo_conf1 . name ]
)
with self . assertRaises ( SystemExit ) , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err :
qubesadmin . tools . qvm_template . qrexec_payload ( args , self . app ,
' qubes-template-fedora \n -32 ' , False )
# Check error message
self . assertTrue ( ' Malformed template name '
in mock_err . getvalue ( ) )
self . assertTrue ( " argument should not contain ' \\ n ' "
in mock_err . getvalue ( ) )
self . assertAllCalled ( )
def test_113_qrexec_payload_enablereponewline_fail ( self ) :
with tempfile . NamedTemporaryFile ( ) as repo_conf1 :
repo_str1 = \
''' [qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl / repodata / repomd . xml . metalink
enabled = 1
fastestmirror = 1
metadata_expire = 7 d
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_conf1 . write ( repo_str1 . encode ( ) )
repo_conf1 . flush ( )
args = argparse . Namespace (
enablerepo = [ ' repo \n 0 ' ] ,
disablerepo = [ ] ,
repoid = [ ' repo1 ' , ' repo2 ' ] ,
releasever = ' 4.1 ' ,
repo_files = [ repo_conf1 . name ]
)
with self . assertRaises ( SystemExit ) , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err :
qubesadmin . tools . qvm_template . qrexec_payload ( args , self . app ,
' qubes-template-fedora-32 ' , False )
# Check error message
self . assertTrue ( ' Malformed --enablerepo '
in mock_err . getvalue ( ) )
self . assertTrue ( " argument should not contain ' \\ n ' "
in mock_err . getvalue ( ) )
self . assertAllCalled ( )
def test_114_qrexec_payload_disablereponewline_fail ( self ) :
with tempfile . NamedTemporaryFile ( ) as repo_conf1 :
repo_str1 = \
''' [qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl / repodata / repomd . xml . metalink
enabled = 1
fastestmirror = 1
metadata_expire = 7 d
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_conf1 . write ( repo_str1 . encode ( ) )
repo_conf1 . flush ( )
args = argparse . Namespace (
enablerepo = [ ] ,
disablerepo = [ ' repo \n 0 ' ] ,
repoid = [ ' repo1 ' , ' repo2 ' ] ,
releasever = ' 4.1 ' ,
repo_files = [ repo_conf1 . name ]
)
with self . assertRaises ( SystemExit ) , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err :
qubesadmin . tools . qvm_template . qrexec_payload ( args , self . app ,
' qubes-template-fedora-32 ' , False )
# Check error message
self . assertTrue ( ' Malformed --disablerepo '
in mock_err . getvalue ( ) )
self . assertTrue ( " argument should not contain ' \\ n ' "
in mock_err . getvalue ( ) )
self . assertAllCalled ( )
def test_115_qrexec_payload_repoidnewline_fail ( self ) :
with tempfile . NamedTemporaryFile ( ) as repo_conf1 :
repo_str1 = \
''' [qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl / repodata / repomd . xml . metalink
enabled = 1
fastestmirror = 1
metadata_expire = 7 d
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_conf1 . write ( repo_str1 . encode ( ) )
repo_conf1 . flush ( )
args = argparse . Namespace (
enablerepo = [ ] ,
disablerepo = [ ] ,
repoid = [ ' repo \n 1 ' , ' repo2 ' ] ,
releasever = ' 4.1 ' ,
repo_files = [ repo_conf1 . name ]
)
with self . assertRaises ( SystemExit ) , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err :
qubesadmin . tools . qvm_template . qrexec_payload ( args , self . app ,
' qubes-template-fedora-32 ' , False )
# Check error message
self . assertTrue ( ' Malformed --repoid '
in mock_err . getvalue ( ) )
self . assertTrue ( " argument should not contain ' \\ n ' "
in mock_err . getvalue ( ) )
self . assertAllCalled ( )
def test_116_qrexec_payload_releasevernewline_fail ( self ) :
with tempfile . NamedTemporaryFile ( ) as repo_conf1 :
repo_str1 = \
''' [qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl / repodata / repomd . xml . metalink
enabled = 1
fastestmirror = 1
metadata_expire = 7 d
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_conf1 . write ( repo_str1 . encode ( ) )
repo_conf1 . flush ( )
args = argparse . Namespace (
enablerepo = [ ] ,
disablerepo = [ ] ,
repoid = [ ' repo1 ' , ' repo2 ' ] ,
releasever = ' 4 \n .1 ' ,
repo_files = [ repo_conf1 . name ]
)
with self . assertRaises ( SystemExit ) , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err :
qubesadmin . tools . qvm_template . qrexec_payload ( args , self . app ,
' qubes-template-fedora-32 ' , False )
# Check error message
self . assertTrue ( ' Malformed --releasever '
in mock_err . getvalue ( ) )
self . assertTrue ( " argument should not contain ' \\ n ' "
in mock_err . getvalue ( ) )
self . assertAllCalled ( )
def test_117_qrexec_payload_specdash_fail ( self ) :
with tempfile . NamedTemporaryFile ( ) as repo_conf1 :
repo_str1 = \
''' [qubes-templates-itl]
name = Qubes Templates repository
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
metalink = https : / / yum . qubes - os . org / r $ releasever / templates - itl / repodata / repomd . xml . metalink
enabled = 1
fastestmirror = 1
metadata_expire = 7 d
gpgcheck = 1
gpgkey = file : / / / usr / share / qubes / repo - templates / keys / RPM - GPG - KEY - qubes - $ releasever - primary
'''
repo_conf1 . write ( repo_str1 . encode ( ) )
repo_conf1 . flush ( )
args = argparse . Namespace (
enablerepo = [ ] ,
disablerepo = [ ] ,
repoid = [ ' repo1 ' , ' repo2 ' ] ,
releasever = ' 4.1 ' ,
repo_files = [ repo_conf1 . name ]
)
with self . assertRaises ( SystemExit ) , \
mock . patch ( ' sys.stderr ' , new = io . StringIO ( ) ) as mock_err :
qubesadmin . tools . qvm_template . qrexec_payload ( args , self . app ,
' --- ' , False )
# Check error message
self . assertTrue ( ' Malformed template name '
in mock_err . getvalue ( ) )
self . assertTrue ( " argument should not be ' --- ' "
in mock_err . getvalue ( ) )
self . assertAllCalled ( )
2020-09-06 19:52:56 +02:00
@mock.patch ( ' qubesadmin.tools.qvm_template.qrexec_payload ' )
def test_120_qrexec_repoquery_success ( self , mock_payload ) :
args = argparse . Namespace ( updatevm = ' test-vm ' )
mock_payload . return_value = ' str1 \n str2 '
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = \
b ' 0 \x00 test-vm class=AppVM state=Halted \n '
self . app . expected_service_calls [
( ' test-vm ' , ' qubes.TemplateSearch ' ) ] = \
b ''' qubes-template-fedora-32|0|4.1|20200101|qubes-templates-itl|1048576|2020-01-23 04:56|GPL|https://qubes-os.org|Qubes template for fedora-32|Qubes template \n for fedora-32 \n |
qubes - template - fedora - 32 | 1 | 4.2 | 20200201 | qubes - templates - itl - testing | 2048576 | 2020 - 02 - 23 04 : 56 | GPLv2 | https : / / qubes - os . org / ? | Qubes template for fedora - 32 v2 | Qubes template \n for fedora - 32 v2 \n |
'''
res = qubesadmin . tools . qvm_template . qrexec_repoquery ( args , self . app ,
' qubes-template-fedora-32 ' )
self . assertEqual ( res , [
qubesadmin . tools . qvm_template . Template (
' fedora-32 ' ,
' 0 ' ,
' 4.1 ' ,
' 20200101 ' ,
' qubes-templates-itl ' ,
1048576 ,
datetime . datetime ( 2020 , 1 , 23 , 4 , 56 ) ,
' GPL ' ,
' https://qubes-os.org ' ,
' Qubes template for fedora-32 ' ,
' Qubes template \n for fedora-32 \n '
) ,
qubesadmin . tools . qvm_template . Template (
' fedora-32 ' ,
' 1 ' ,
' 4.2 ' ,
' 20200201 ' ,
' qubes-templates-itl-testing ' ,
2048576 ,
datetime . datetime ( 2020 , 2 , 23 , 4 , 56 ) ,
' GPLv2 ' ,
' https://qubes-os.org/? ' ,
' Qubes template for fedora-32 v2 ' ,
' Qubes template \n for fedora-32 v2 \n '
)
] )
self . assertEqual ( self . app . service_calls , [
( ' test-vm ' , ' qubes.TemplateSearch ' ,
{ ' filter_esc ' : True , ' stdout ' : subprocess . PIPE } ) ,
( ' test-vm ' , ' qubes.TemplateSearch ' , b ' str1 \n str2 ' )
] )
self . assertEqual ( mock_payload . mock_calls , [
mock . call ( args , self . app , ' qubes-template-fedora-32 ' , False )
] )
self . assertAllCalled ( )
@mock.patch ( ' qubesadmin.tools.qvm_template.qrexec_payload ' )
def test_121_qrexec_repoquery_refresh_success ( self , mock_payload ) :
args = argparse . Namespace ( updatevm = ' test-vm ' )
mock_payload . return_value = ' str1 \n str2 '
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = \
b ' 0 \x00 test-vm class=AppVM state=Halted \n '
self . app . expected_service_calls [
( ' test-vm ' , ' qubes.TemplateSearch ' ) ] = \
b ''' qubes-template-fedora-32|0|4.1|20200101|qubes-templates-itl|1048576|2020-01-23 04:56|GPL|https://qubes-os.org|Qubes template for fedora-32|Qubes template \n for fedora-32 \n |
qubes - template - fedora - 32 | 1 | 4.2 | 20200201 | qubes - templates - itl - testing | 2048576 | 2020 - 02 - 23 04 : 56 | GPLv2 | https : / / qubes - os . org / ? | Qubes template for fedora - 32 v2 | Qubes template \n for fedora - 32 v2 \n |
'''
res = qubesadmin . tools . qvm_template . qrexec_repoquery ( args , self . app ,
' qubes-template-fedora-32 ' , True )
self . assertEqual ( res , [
qubesadmin . tools . qvm_template . Template (
' fedora-32 ' ,
' 0 ' ,
' 4.1 ' ,
' 20200101 ' ,
' qubes-templates-itl ' ,
1048576 ,
datetime . datetime ( 2020 , 1 , 23 , 4 , 56 ) ,
' GPL ' ,
' https://qubes-os.org ' ,
' Qubes template for fedora-32 ' ,
' Qubes template \n for fedora-32 \n '
) ,
qubesadmin . tools . qvm_template . Template (
' fedora-32 ' ,
' 1 ' ,
' 4.2 ' ,
' 20200201 ' ,
' qubes-templates-itl-testing ' ,
2048576 ,
datetime . datetime ( 2020 , 2 , 23 , 4 , 56 ) ,
' GPLv2 ' ,
' https://qubes-os.org/? ' ,
' Qubes template for fedora-32 v2 ' ,
' Qubes template \n for fedora-32 v2 \n '
)
] )
self . assertEqual ( self . app . service_calls , [
( ' test-vm ' , ' qubes.TemplateSearch ' ,
{ ' filter_esc ' : True , ' stdout ' : subprocess . PIPE } ) ,
( ' test-vm ' , ' qubes.TemplateSearch ' , b ' str1 \n str2 ' )
] )
self . assertEqual ( mock_payload . mock_calls , [
mock . call ( args , self . app , ' qubes-template-fedora-32 ' , True )
] )
self . assertAllCalled ( )
@mock.patch ( ' qubesadmin.tools.qvm_template.qrexec_payload ' )
def test_122_qrexec_repoquery_ignorenonspec_success ( self , mock_payload ) :
args = argparse . Namespace ( updatevm = ' test-vm ' )
mock_payload . return_value = ' str1 \n str2 '
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = \
b ' 0 \x00 test-vm class=AppVM state=Halted \n '
self . app . expected_service_calls [
( ' test-vm ' , ' qubes.TemplateSearch ' ) ] = \
b ''' qubes-template-debian-10|1|4.2|20200201|qubes-templates-itl-testing|2048576|2020-02-23 04:56|GPLv2|https://qubes-os.org/?|Qubes template for debian-10|Qubes template for debian-10 \n |
qubes - template - fedora - 32 | 0 | 4.1 | 20200101 | qubes - templates - itl | 1048576 | 2020 - 01 - 23 04 : 56 | GPL | https : / / qubes - os . org | Qubes template for fedora - 32 | Qubes template for fedora - 32 \n |
'''
res = qubesadmin . tools . qvm_template . qrexec_repoquery ( args , self . app ,
' qubes-template-fedora-32 ' )
self . assertEqual ( res , [
qubesadmin . tools . qvm_template . Template (
' fedora-32 ' ,
' 0 ' ,
' 4.1 ' ,
' 20200101 ' ,
' qubes-templates-itl ' ,
1048576 ,
datetime . datetime ( 2020 , 1 , 23 , 4 , 56 ) ,
' GPL ' ,
' https://qubes-os.org ' ,
' Qubes template for fedora-32 ' ,
' Qubes template for fedora-32 \n '
)
] )
self . assertEqual ( self . app . service_calls , [
( ' test-vm ' , ' qubes.TemplateSearch ' ,
{ ' filter_esc ' : True , ' stdout ' : subprocess . PIPE } ) ,
( ' test-vm ' , ' qubes.TemplateSearch ' , b ' str1 \n str2 ' )
] )
self . assertEqual ( mock_payload . mock_calls , [
mock . call ( args , self . app , ' qubes-template-fedora-32 ' , False )
] )
self . assertAllCalled ( )
@mock.patch ( ' qubesadmin.tools.qvm_template.qrexec_payload ' )
def test_123_qrexec_repoquery_ignorebadname_success ( self , mock_payload ) :
args = argparse . Namespace ( updatevm = ' test-vm ' )
mock_payload . return_value = ' str1 \n str2 '
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = \
b ' 0 \x00 test-vm class=AppVM state=Halted \n '
self . app . expected_service_calls [
( ' test-vm ' , ' qubes.TemplateSearch ' ) ] = \
b ''' template-fedora-32|1|4.2|20200201|qubes-templates-itl-testing|2048576|2020-02-23 04:56|GPLv2|https://qubes-os.org/?|Qubes template for fedora-32 v2|Qubes template \n for fedora-32 v2 \n |
qubes - template - fedora - 32 | 0 | 4.1 | 20200101 | qubes - templates - itl | 1048576 | 2020 - 01 - 23 04 : 56 | GPL | https : / / qubes - os . org | Qubes template for fedora - 32 | Qubes template for fedora - 32 \n |
'''
res = qubesadmin . tools . qvm_template . qrexec_repoquery ( args , self . app ,
' qubes-template-fedora-32 ' )
self . assertEqual ( res , [
qubesadmin . tools . qvm_template . Template (
' fedora-32 ' ,
' 0 ' ,
' 4.1 ' ,
' 20200101 ' ,
' qubes-templates-itl ' ,
1048576 ,
datetime . datetime ( 2020 , 1 , 23 , 4 , 56 ) ,
' GPL ' ,
' https://qubes-os.org ' ,
' Qubes template for fedora-32 ' ,
' Qubes template for fedora-32 \n '
)
] )
self . assertEqual ( self . app . service_calls , [
( ' test-vm ' , ' qubes.TemplateSearch ' ,
{ ' filter_esc ' : True , ' stdout ' : subprocess . PIPE } ) ,
( ' test-vm ' , ' qubes.TemplateSearch ' , b ' str1 \n str2 ' )
] )
self . assertEqual ( mock_payload . mock_calls , [
mock . call ( args , self . app , ' qubes-template-fedora-32 ' , False )
] )
self . assertAllCalled ( )
@mock.patch ( ' qubesadmin.tools.qvm_template.qrexec_payload ' )
def test_124_qrexec_repoquery_searchfail_fail ( self , mock_payload ) :
args = argparse . Namespace ( updatevm = ' test-vm ' )
mock_payload . return_value = ' str1 \n str2 '
self . app . expected_calls [ ( ' dom0 ' , ' admin.vm.List ' , None , None ) ] = \
b ' 0 \x00 test-vm class=AppVM state=Halted \n '
with mock . patch ( ' qubesadmin.tests.TestProcess.wait ' ) \
as mock_wait :
mock_wait . return_value = 1
with self . assertRaises ( ConnectionError ) :
qubesadmin . tools . qvm_template . qrexec_repoquery ( args , self . app ,
' qubes-template-fedora-32 ' )
self . assertEqual ( self . app . service_calls , [
( ' test-vm ' , ' qubes.TemplateSearch ' ,
{ ' filter_esc ' : True , ' stdout ' : subprocess . PIPE } ) ,
( ' test-vm ' , ' qubes.TemplateSearch ' , b ' str1 \n str2 ' )
] )
self . assertEqual ( mock_payload . mock_calls , [
mock . call ( args , self . app , ' qubes-template-fedora-32 ' , False )
] )
self . assertAllCalled ( )
# TODO: Also test feeding broken data to qrexec_repoquery