From 04ad224a9d672ba100aea6c86bd2633ff6482ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sun, 16 Jul 2017 05:22:13 +0200 Subject: [PATCH] tests: add v4 (Qubes 4.0) backup format tests, move qubes.xml Move qubes.xml to be tested into separate files. The backup tests script is long enouch already. --- ci/coveragerc | 2 + .../tests/backup/backupcompatibility.py | 636 ++++++++++++++++-- qubesadmin/tests/backup/v3-qubes.xml | 18 + qubesadmin/tests/backup/v4-qubes.xml | 526 +++++++++++++++ setup.py | 3 + 5 files changed, 1134 insertions(+), 51 deletions(-) create mode 100644 qubesadmin/tests/backup/v3-qubes.xml create mode 100644 qubesadmin/tests/backup/v4-qubes.xml diff --git a/ci/coveragerc b/ci/coveragerc index 37b61cc..98a5244 100644 --- a/ci/coveragerc +++ b/ci/coveragerc @@ -1,3 +1,5 @@ [run] source = qubesadmin omit = qubesadmin/tests/* +# breaks backup tests for unknown reason +# concurrency=multiprocessing diff --git a/qubesadmin/tests/backup/backupcompatibility.py b/qubesadmin/tests/backup/backupcompatibility.py index 5569f0a..d5b98c6 100644 --- a/qubesadmin/tests/backup/backupcompatibility.py +++ b/qubesadmin/tests/backup/backupcompatibility.py @@ -20,11 +20,15 @@ # import functools import tempfile +import unittest +from distutils import spawn from multiprocessing import Queue import os import subprocess +import logging + try: import unittest.mock as mock except ImportError: @@ -32,54 +36,15 @@ except ImportError: import re import multiprocessing - +import pkg_resources import sys import qubesadmin.backup.core2 +import qubesadmin.backup.core3 import qubesadmin.storage import qubesadmin.tests import qubesadmin.tests.backup -QUBESXML_R2B2 = ''' - - - - - - - - - - - - - - - - - -''' - -QUBESXML_R2 = ''' - - - - - - - - - - - - - - - - - - -''' MANGLED_SUBDIRS_R2 = { "test-work": "vm5", @@ -90,6 +55,16 @@ MANGLED_SUBDIRS_R2 = { "test-testhvm": "vm14", "test-net": "vm16", } +MANGLED_SUBDIRS_R4 = { + "test-work": "vm3", + "test-fedora-25-clone": "vm7", + "test-custom-template-appvm": "vm31", + "test-standalonevm": "vm4", + "test-proxy": "vm30", + "test-hvm": "vm9", + "test-net": "vm6", + "test-d8test": "vm20", +} APPTEMPLATE_R2B2 = ''' [Desktop Entry] @@ -153,6 +128,14 @@ compressed={compressed} compression-filter=gzip ''' +BACKUP_HEADER_R4 = '''version=4 +hmac-algorithm=scrypt +encrypted=True +compressed={compressed} +compression-filter=gzip +backup-id=20161020T123455-1234 +''' + parsed_qubes_xml_r2 = { 'domains': { 'dom0': { @@ -424,13 +407,314 @@ parsed_qubes_xml_r2 = { }, } +parsed_qubes_xml_v4 = { + 'domains': { + 'dom0': { + 'klass': 'AdminVM', + 'label': 'black', + 'properties': {}, + 'devices': {}, + 'tags': set(), + 'features': {}, + 'template': None, + 'backup_path': None, + 'included_in_backup': False, + }, + 'fedora-25': { + 'klass': 'TemplateVM', + 'label': 'black', + 'properties': {}, + 'devices': {}, + 'tags': {'created-by-test-work'}, + 'features': { + 'gui': '1', + 'qrexec': 'True', + 'updates-available': False + }, + 'template': None, + 'backup_path': None, + 'included_in_backup': False, + }, + 'fedora-25-lvm': { + 'klass': 'TemplateVM', + 'label': 'black', + 'properties': { + 'maxmem': '4000', + }, + 'devices': {}, + 'tags': set(), + 'features': {}, + 'template': None, + 'backup_path': None, + 'included_in_backup': False, + }, + 'debian-8': { + 'klass': 'TemplateVM', + 'label': 'black', + 'properties': {}, + 'devices': {}, + 'tags': {'created-by-dom0'}, + 'features': { + 'gui': '1', + 'qrexec': 'True', + 'updates-available': False}, + 'template': None, + 'backup_path': None, + 'included_in_backup': False, + }, + 'sys-net': { + 'klass': 'AppVM', + 'label': 'red', + 'properties': { + 'hvm': 'False', + 'kernelopts': 'nopat i8042.nokbd i8042.noaux', + 'maxmem': '300', + 'memory': '300', + 'netvm': None, + 'default_user': 'user', + 'provides_network': 'True'}, + 'devices': { + 'pci': { + ('dom0', '02_00.0'): {}, + } + }, + 'tags': set(), + 'features': { + 'service.clocksync': '1', + 'service.meminfo-writer': False + }, + 'template': 'fedora-25', + 'backup_path': None, + 'included_in_backup': False, + }, + 'sys-firewall': { + 'klass': 'AppVM', + 'label': 'green', + 'properties': { + 'autostart': 'True', + 'memory': '500', + 'provides_network': 'True' + }, + 'devices': {}, + 'tags': set(), + 'features': {}, + 'template': 'fedora-25', + 'backup_path': None, + 'included_in_backup': False, + }, + 'test-d8test': { + 'klass': 'AppVM', + 'label': 'gray', + 'properties': {'debug': 'True', 'kernel': None}, + 'devices': {}, + 'tags': {'created-by-dom0'}, + 'features': {}, + 'template': 'debian-8', + 'backup_path': 'appvms/test-d8test', + 'included_in_backup': True, + }, + 'fedora-25-dvm': { + 'klass': 'AppVM', + 'label': 'red', + 'properties': { + 'dispvm_allowed': 'True', + 'vcpus': '1', + }, + 'devices': {}, + 'tags': set(), + 'features': { + 'internal': '1', 'service.meminfo-writer': '1'}, + 'template': 'fedora-25', + 'backup_path': None, + 'included_in_backup': False, + }, + 'fedora-25-clone-dvm': { + 'klass': 'AppVM', + 'label': 'red', + 'properties': { + 'vcpus': '1', + 'dispvm_allowed': 'True', + }, + 'devices': {}, + 'tags': set(), + 'features': { + 'internal': '1', 'service.meminfo-writer': '1'}, + 'template': 'test-fedora-25-clone', + 'backup_path': None, + 'included_in_backup': False, + }, + 'vault': { + 'klass': 'AppVM', + 'label': 'black', + 'properties': {'hvm': 'False', 'maxmem': '1536', 'netvm': None}, + 'devices': {}, + 'tags': set(), + 'features': {}, + 'template': 'fedora-25', + 'backup_path': None, + 'included_in_backup': False, + }, + 'personal': { + 'klass': 'AppVM', + 'label': 'yellow', + 'properties': {'netvm': 'sys-firewall'}, + 'devices': {}, + 'tags': set(), + 'features': { + 'feat1': '1', + 'feat2': False, + 'feat32': '1', + 'featdis': False, + 'xxx': '1' + }, + 'template': 'fedora-25', + 'backup_path': None, + 'included_in_backup': False, + }, + 'untrusted': { + 'klass': 'AppVM', + 'label': 'red', + 'properties': { + 'netvm': None, + 'backup_timestamp': '1474318497', + 'default_dispvm': 'fedora-25-clone-dvm', + }, + 'devices': {}, + 'tags': set(), + 'features': {'service.meminfo-writer': '1'}, + 'template': 'fedora-25', + 'backup_path': None, + 'included_in_backup': False, + }, + 'sys-usb': { + 'klass': 'AppVM', + 'label': 'red', + 'properties': { + 'hvm': 'False', + 'autostart': 'True', + 'maxmem': '400', + 'provides_network': 'True', + }, + 'devices': {}, + 'tags': set(), + 'features': { + 'service.meminfo-writer': False, + 'service.network-manager': False, + }, + 'template': 'fedora-25', + 'backup_path': None, + 'included_in_backup': False, + }, + 'test-proxy': { + 'klass': 'AppVM', + 'label': 'red', + 'properties': {'netvm': 'sys-net', 'provides_network': 'True'}, + 'devices': {}, + 'tags': {'created-by-dom0'}, + 'features': {}, + 'template': 'debian-8', + 'backup_path': 'appvms/test-proxy', + 'included_in_backup': True, + }, + 'test-hvm': { + 'klass': 'StandaloneVM', + 'label': 'purple', + 'properties': {'hvm': 'True', 'maxmem': '4000'}, + 'devices': {}, + 'tags': set(), + 'features': {'service.meminfo-writer': False}, + 'template': None, + 'backup_path': 'appvms/test-hvm', + 'included_in_backup': True, + 'root_size': 2097664, + }, + 'test-work': { + 'klass': 'AppVM', + 'label': 'green', + 'properties': { + 'ip': '192.168.0.1', + 'maxmem': '4000', + 'memory': '400'}, + 'devices': {}, + 'tags': {'tag1', 'tag2'}, + 'features': {'service.meminfo-writer': '1'}, + 'template': 'fedora-25', + 'backup_path': 'appvms/test-work', + 'included_in_backup': True, + }, + 'test-fedora-25-clone': { + 'klass': 'TemplateVM', + 'label': 'black', + 'properties': {'maxmem': '4000'}, + 'devices': {}, + 'tags': set(), + 'features': {'service.meminfo-writer': '1'}, + 'template': None, + 'backup_path': 'vm-templates/test-fedora-25-clone', + 'included_in_backup': True, + }, + 'test-custom-template-appvm': { + 'klass': 'AppVM', + 'label': 'yellow', + 'properties': {'debug': 'True', 'kernel': None}, + 'devices': {}, + 'tags': {'created-by-dom0'}, + 'features': {}, + 'template': 'test-fedora-25-clone', + 'backup_path': 'appvms/test-custom-template-appvm', + 'included_in_backup': True, + }, + 'test-standalonevm': { + 'klass': 'StandaloneVM', + 'label': 'blue', + 'properties': {'maxmem': '4000'}, + 'devices': {}, + 'tags': set(), + 'features': {}, + 'template': None, + 'backup_path': 'appvms/test-standalonevm', + 'included_in_backup': True, + 'root_size': 2097664, + }, + 'test-net': { + 'klass': 'AppVM', + 'label': 'red', + 'properties': { + 'maxmem': '300', + 'memory': '300', + 'netvm': None, + 'provides_network': 'True' + }, + 'devices': { + 'pci': { + ('dom0', '03_00.0'): {}, + } + }, + 'tags': set(), + 'features': { + 'service.ntpd': False, + 'service.meminfo-writer': False + }, + 'template': 'fedora-25', + 'backup_path': 'appvms/test-net', + 'included_in_backup': True, + }, + }, + 'globals': { + 'default_template': 'fedora-25', + 'default_kernel': '4.9.31-17', + 'default_netvm': 'sys-firewall', + 'default_dispvm': 'fedora-25-dvm', + #'default_fw_netvm': 'sys-net', + 'clockvm': 'sys-net', + 'updatevm': 'sys-firewall' + }, +} + class TC_00_QubesXML(qubesadmin.tests.QubesTestCase): - def assertCorrectlyConverted(self, xml_data, expected_data): - with tempfile.NamedTemporaryFile() as qubes_xml: - qubes_xml.file.write(xml_data.encode()) - backup_app = qubesadmin.backup.core2.Core2Qubes(qubes_xml.name) + def assertCorrectlyConverted(self, backup_app, expected_data): self.assertCountEqual(backup_app.domains.keys(), expected_data['domains'].keys()) for vm in expected_data['domains']: @@ -458,7 +742,19 @@ class TC_00_QubesXML(qubesadmin.tests.QubesTestCase): self.assertEqual(backup_app.globals, expected_data['globals']) def test_000_qubes_xml_r2(self): - self.assertCorrectlyConverted(QUBESXML_R2, parsed_qubes_xml_r2) + xml_data = pkg_resources.resource_string(__name__, 'v3-qubes.xml') + with tempfile.NamedTemporaryFile() as qubes_xml: + qubes_xml.file.write(xml_data) + backup_app = qubesadmin.backup.core2.Core2Qubes(qubes_xml.name) + self.assertCorrectlyConverted(backup_app, parsed_qubes_xml_r2) + + def test_010_qubes_xml_r4(self): + self.maxDiff = None + xml_data = pkg_resources.resource_string(__name__, 'v4-qubes.xml') + with tempfile.NamedTemporaryFile() as qubes_xml: + qubes_xml.file.write(xml_data) + backup_app = qubesadmin.backup.core3.Core3Qubes(qubes_xml.name) + self.assertCorrectlyConverted(backup_app, parsed_qubes_xml_v4) # backup code use multiprocessing, synchronize with main process class AppProxy(object): @@ -655,6 +951,91 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase): "vm-templates/test-template-clone")), appmenus_list) + def create_v4_files(self): + appmenus_list = [ + "firefox", "gnome-terminal", "evince", "evolution", + "mozilla-thunderbird", "libreoffice-startcenter", "nautilus", + "gedit", "gpk-update-viewer", "gpk-application" + ] + + os.mkdir(self.fullpath("appvms")) + os.mkdir(self.fullpath("vm-templates")) + + # normal AppVMs + for vm in ('test-work', 'test-d8test', 'test-proxy', + 'test-custom-template-appvm', 'test-net'): + os.mkdir(self.fullpath('appvms/{}'.format(vm))) + self.create_whitelisted_appmenus(self.fullpath( + 'appvms/{}/whitelisted-appmenus.list'.format(vm))) + self.create_private_img(self.fullpath('appvms/{}/private.img'.format( + vm))) + + # StandaloneVMs + for vm in ('test-standalonevm', 'test-hvm'): + os.mkdir(self.fullpath('appvms/{}'.format(vm))) + self.create_whitelisted_appmenus(self.fullpath( + 'appvms/{}/whitelisted-appmenus.list'.format(vm))) + self.create_private_img(self.fullpath( + 'appvms/{}/private.img'.format(vm))) + self.create_sparse( + self.fullpath('appvms/{}/root.img'.format(vm)), 10*2**30) + self.fill_image(self.fullpath('appvms/{}/root.img'.format(vm)), + 1024*1024, True, + signature='{}/root'.format(vm).encode()) + + # only for Linux one + os.mkdir(self.fullpath('appvms/test-standalonevm/apps.templates')) + self.create_appmenus( + self.fullpath('appvms/test-standalonevm/apps.templates'), + APPTEMPLATE_R2B2, + appmenus_list) + + # Custom template + os.mkdir(self.fullpath("vm-templates/test-fedora-25-clone")) + self.create_private_img( + self.fullpath("vm-templates/test-fedora-25-clone/private.img")) + self.create_sparse(self.fullpath( + "vm-templates/test-fedora-25-clone/root.img"), 10*2**20) + self.fill_image(self.fullpath( + "vm-templates/test-fedora-25-clone/root.img"), 1*2**20, True, + signature=b'test-fedora-25-clone/root') + self.create_volatile_img(self.fullpath( + "vm-templates/test-fedora-25-clone/volatile.img")) + self.create_whitelisted_appmenus(self.fullpath( + "vm-templates/test-fedora-25-clone/whitelisted-appmenus.list")) + self.create_whitelisted_appmenus(self.fullpath( + "vm-templates/test-fedora-25-clone/vm-whitelisted-appmenus.list")) + os.mkdir( + self.fullpath("vm-templates/test-fedora-25-clone/apps.templates")) + self.create_appmenus( + self.fullpath("vm-templates/test-fedora-25-clone/apps.templates"), + APPTEMPLATE_R2B2, + appmenus_list) + os.mkdir(self.fullpath("vm-templates/test-fedora-25-clone/apps")) + self.create_appmenus( + self.fullpath("vm-templates/test-fedora-25-clone/apps"), + APPTEMPLATE_R2B2.replace("%VMNAME%", "test-fedora-25-clone") + .replace("%VMDIR%", self.fullpath( + "vm-templates/test-fedora-25-clone")), + appmenus_list) + + def scrypt_encrypt(self, f_name, output_name=None, password='qubes', + basedir=None): + if basedir is None: + basedir = self.backupdir + if output_name is None: + output_name = f_name + '.enc' + if f_name == 'backup-header': + scrypt_pass = 'backup-header!' + password + else: + scrypt_pass = '20161020T123455-1234!{}!{}'.format(f_name, password) + p = subprocess.Popen(['scrypt', 'enc', '-P', '-t', '0.1', + os.path.join(basedir, f_name), os.path.join(basedir, output_name)], + stdin=subprocess.PIPE) + p.communicate(scrypt_pass.encode()) + assert p.wait() == 0 + return output_name + def calculate_hmac(self, f_name, algorithm="sha512", password="qubes"): with open(self.fullpath(f_name), "r") as f_data: with open(self.fullpath(f_name+".hmac"), "w") as f_hmac: @@ -715,6 +1096,42 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase): self.append_backup_stream(part_with_dir+".hmac", stream, basedir=self.fullpath("stage1")) + def handle_v4_file(self, f_name, subdir, stream, compressed=True): + # create inner archive + tar_cmdline = ["tar", "-Pc", '--sparse', + '-C', self.fullpath(os.path.dirname(f_name)), + '--xform', 's:^%s:%s\\0:' % ( + os.path.basename(f_name), + subdir), + os.path.basename(f_name) + ] + if compressed: + tar_cmdline.insert(-1, "--use-compress-program=%s" % "gzip") + tar = subprocess.Popen(tar_cmdline, stdout=subprocess.PIPE) + data = tar.stdout + + stage1_dir = self.fullpath(os.path.join("stage1", subdir)) + if not os.path.exists(stage1_dir): + os.makedirs(stage1_dir) + subprocess.check_call(["split", "--numeric-suffixes", + "--suffix-length=3", + "--bytes="+str(100*1024*1024), "-", + os.path.join(stage1_dir, + os.path.basename(f_name+"."))], + stdin=data) + data.close() + + for part in sorted(os.listdir(stage1_dir)): + if not re.match( + r"^{}.[0-9][0-9][0-9]$".format(os.path.basename(f_name)), + part): + continue + part_with_dir = os.path.join(subdir, part) + f_name = self.scrypt_encrypt(part_with_dir, + basedir=self.fullpath('stage1')) + self.append_backup_stream(f_name, stream, + basedir=self.fullpath("stage1")) + def create_v3_backup(self, encrypted=True, compressed=True): """ Create "backup format 3" backup - used in R2 and R3.0 @@ -732,15 +1149,15 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase): self.calculate_hmac("backup-header") self.append_backup_stream("backup-header", output) self.append_backup_stream("backup-header.hmac", output) - with open(self.fullpath("qubes.xml"), "w") as f: + with open(self.fullpath("qubes.xml"), "wb") as f: + qubesxml = pkg_resources.resource_string(__name__, 'v3-qubes.xml') if encrypted: - qubesxml = QUBESXML_R2 for vmname, subdir in MANGLED_SUBDIRS_R2.items(): - qubesxml = re.sub(r"[a-z-]*/{}".format(vmname), - subdir, qubesxml) + qubesxml = re.sub(r"[a-z-]*/{}".format(vmname).encode(), + subdir.encode(), qubesxml) f.write(qubesxml) else: - f.write(QUBESXML_R2) + f.write(qubesxml) self.handle_v3_file("qubes.xml", "", output, encrypted=encrypted, compressed=compressed) @@ -770,6 +1187,44 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase): output.close() + def create_v4_backup(self, compressed=True): + """ + Create "backup format 4" backup - used in R4.0 + + :param compressed: Should the backup be compressed + :return: + """ + output = open(self.fullpath("backup.bin"), "w") + with open(self.fullpath("backup-header"), "w") as f: + f.write(BACKUP_HEADER_R4.format( + compressed=str(compressed) + )) + self.scrypt_encrypt("backup-header", output_name='backup-header.hmac') + self.append_backup_stream("backup-header", output) + self.append_backup_stream("backup-header.hmac", output) + with open(self.fullpath("qubes.xml"), "wb") as f: + qubesxml = pkg_resources.resource_string(__name__, 'v4-qubes.xml') + for vmname, subdir in MANGLED_SUBDIRS_R4.items(): + qubesxml = re.sub( + r'backup-path">[a-z-]*/{}'.format(vmname).encode(), + ('backup-path">' + subdir).encode(), + qubesxml) + f.write(qubesxml) + + self.handle_v4_file("qubes.xml", "", output, compressed=compressed) + + self.create_v4_files() + for vm_type in ["appvms", "vm-templates"]: + for vm_name in os.listdir(self.fullpath(vm_type)): + vm_dir = os.path.join(vm_type, vm_name) + for f_name in os.listdir(self.fullpath(vm_dir)): + subdir = MANGLED_SUBDIRS_R4[vm_name] + self.handle_v4_file( + os.path.join(vm_dir, f_name), + subdir+'/', output, compressed=compressed) + + output.close() + def setup_expected_calls(self, parsed_qubes_xml, templates_map=None): if templates_map is None: templates_map = {} @@ -887,6 +1342,10 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase): (name, 'admin.vm.feature.Set', feature, str(value).encode())] = b'0\0' + for tag in vm['tags']: + self.app.expected_calls[ + (name, 'admin.vm.tag.Set', tag, None)] = b'0\0' + orig_admin_vm_list = self.app.expected_calls[ ('dom0', 'admin.vm.List', None, None)] self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \ @@ -957,6 +1416,81 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase): self.assertAllCalled() + @unittest.skipUnless(spawn.find_executable('scrypt'), + "scrypt not installed") + def test_230_r4(self): + self.create_v4_backup(False) + self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = ( + b'0\0dom0 class=AdminVM state=Running\n' + b'fedora-25 class=TemplateVM state=Halted\n' + b'testvm class=AppVM state=Running\n' + b'sys-net class=AppVM state=Running\n' + ) + self.app.expected_calls[ + ('dom0', 'admin.property.Get', 'default_template', None)] = \ + b'0\0default=no type=vm fedora-25' + self.app.expected_calls[ + ('sys-net', 'admin.vm.property.Get', 'provides_network', None)] = \ + b'0\0default=no type=bool True' + self.setup_expected_calls(parsed_qubes_xml_v4, templates_map={ + 'debian-8': 'fedora-25' + }) + + qubesd_calls_queue = multiprocessing.Queue() + + with mock.patch('qubesadmin.storage.Volume', + functools.partial(MockVolume, qubesd_calls_queue)): + self.restore_backup(self.fullpath("backup.bin"), options={ + 'use-default-template': True, + 'use-default-netvm': True, + }) + + # retrieve calls from other multiprocess.Process instances + while not qubesd_calls_queue.empty(): + call_args = qubesd_calls_queue.get() + self.app.qubesd_call(*call_args) + qubesd_calls_queue.close() + + self.assertAllCalled() + + @unittest.skipUnless(spawn.find_executable('scrypt'), + "scrypt not installed") + def test_230_r4_compressed(self): + self.create_v4_backup(True) + + self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = ( + b'0\0dom0 class=AdminVM state=Running\n' + b'fedora-25 class=TemplateVM state=Halted\n' + b'testvm class=AppVM state=Running\n' + b'sys-net class=AppVM state=Running\n' + ) + self.app.expected_calls[ + ('dom0', 'admin.property.Get', 'default_template', None)] = \ + b'0\0default=no type=vm fedora-25' + self.app.expected_calls[ + ('sys-net', 'admin.vm.property.Get', 'provides_network', None)] = \ + b'0\0default=no type=bool True' + self.setup_expected_calls(parsed_qubes_xml_v4, templates_map={ + 'debian-8': 'fedora-25' + }) + + qubesd_calls_queue = multiprocessing.Queue() + + with mock.patch('qubesadmin.storage.Volume', + functools.partial(MockVolume, qubesd_calls_queue)): + self.restore_backup(self.fullpath("backup.bin"), options={ + 'use-default-template': True, + 'use-default-netvm': True, + }) + + # retrieve calls from other multiprocess.Process instances + while not qubesd_calls_queue.empty(): + call_args = qubesd_calls_queue.get() + self.app.qubesd_call(*call_args) + qubesd_calls_queue.close() + + self.assertAllCalled() + class TC_11_BackupCompatibilityIntoLVM(TC_10_BackupCompatibility): storage_pool = 'some-pool' diff --git a/qubesadmin/tests/backup/v3-qubes.xml b/qubesadmin/tests/backup/v3-qubes.xml new file mode 100644 index 0000000..1d60230 --- /dev/null +++ b/qubesadmin/tests/backup/v3-qubes.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/qubesadmin/tests/backup/v4-qubes.xml b/qubesadmin/tests/backup/v4-qubes.xml new file mode 100644 index 0000000..f02c4ac --- /dev/null +++ b/qubesadmin/tests/backup/v4-qubes.xml @@ -0,0 +1,526 @@ + + + + + + + + + + + + + + + + + + sys-net + fedora-25-dvm + 4.9.31-17 + sys-firewall + fedora-25 + sys-firewall + + + + + True + + label-5 + test-d8test + 20 + 9204481c-7e37-42a6-8a66-b4cc63d65f11 + debian-8 + + + True + appvms/test-d8test + 20971520 + + + + + + + + + + + + + + + + label-1 + test-proxy + 30 + 367c64e6-ab8c-42df-91b6-c9d4c7d015f2 + debian-8 + True + sys-net + + + True + appvms/test-proxy + 209715200 + + + + + + + + + + + + + + + + label-8 + debian-8 + 16 + 0e2fa953-016f-4486-9e36-c9b386fc2bac + + + True + + 1 + + + + + + + + + + + + + + + + label-8 + + + + + + + + + + True + + label-3 + test-custom-template-appvm + 31 + 1bdb7b32-8a4b-4bb7-8da0-6b06494f642c + test-fedora-25-clone + + + True + appvms/test-custom-template-appvm + 20971520 + + + + + + + + + + + + + + + + + label-8 + 4000 + test-fedora-25-clone + 7 + e3b8d458-8c4c-4ccb-b00d-b7ae454cb08f + + + 1 + True + vm-templates/test-fedora-25-clone + 2097152000 + + + + + + + + + + + + + + True + label-1 + fedora-25-clone-dvm + 10 + 30daa6b5-693b-460a-9da7-99078a2d9d14 + test-fedora-25-clone + 1 + + + 1 + 1 + + + + + + + + + + + + + + True + label-1 + fedora-25-dvm + 10 + 30daa6b5-693b-460a-9da7-99078a2d9d14 + fedora-25 + 1 + + + 1 + 1 + + + + + + + + + + + + + + label-8 + 4000 + fedora-25-lvm + 14 + 20785bf4-42fa-4035-ab95-c1bf054c153a + + + + + + + + + + + + + + + label-8 + fedora-25 + 8 + 51870d8e-2e71-41d2-9582-30661f611004 + + + True + + 1 + + + + + + + + + + + + + + + + True + label-7 + 4000 + test-hvm + 9 + 9909066b-0f03-4725-ad9e-fa3561d5566e + + + + True + appvms/test-hvm + 2097152000 + + + + + + + + + + + + + + 1474318497 + label-1 + untrusted + 11 + 359b8e38-9e50-46a3-a42c-8d3bb15d3890 + fedora-25-clone-dvm + + fedora-25 + + + 1 + + + + + + + + + + + + + + label-3 + personal + 22 + efa8ddc4-6661-4231-9bfd-ef34907da358 + sys-firewall + fedora-25 + + + 1 + 1 + + + 1 + + + + + + + + + + + + + + True + label-4 + 500 + sys-firewall + True + 21 + 40f0775a-c259-44bc-be57-6148c67c42c7 + fedora-25 + + + + + + + + + + + + + + + + user + False + label-1 + 300 + 300 + sys-net + + True + nopat i8042.nokbd i8042.noaux + 2 + eb8b1680-d4fa-449b-8baa-b5146d9b62b7 + fedora-25 + + + + 1 + + + + + + + + + + + + + + + + + label-1 + 300 + test-net + + 300 + True + 6 + d5e9a792-9247-4f6f-a936-b7c65a1adfac + fedora-25 + + + + + True + appvms/test-net + 209715200 + + + + + + + + + + + + + + + + True + label-1 + False + 400 + sys-usb + 5 + 0da5616e-f2db-4c17-9c0d-cdef2e728344 + fedora-25 + True + + + + + + + + + + + + + + + + + + + + + + + + + label-8 + vault + + 13 + d5284828-988d-46e2-8388-a09c495475e3 + fedora-25 + False + 1536 + + + + + + + + + + + + + + + 192.168.0.1 + label-4 + 4000 + 400 + test-work + 3 + 07c17d1e-0982-417d-b19e-a81d51bed423 + fedora-25 + + + 1 + True + appvms/test-work + 2097152000 + + + + + + + + + + + + + + + + + label-6 + 4000 + test-standalonevm + 4 + e8034b8a-29b3-4f02-b8cb-05cd74a4bb68 + + + True + appvms/test-standalonevm + 2097152000 + + + + + + + + + + + diff --git a/setup.py b/setup.py index 6283ecd..25b04dd 100644 --- a/setup.py +++ b/setup.py @@ -33,6 +33,9 @@ if __name__ == '__main__': license='LGPL2.1+', url='https://www.qubes-os.org/', packages=setuptools.find_packages(exclude=exclude), + package_data={ + 'qubesadmin.tests.backup': ['*.xml'], + }, entry_points={ 'console_scripts': list(get_console_scripts()), 'qubesadmin.vm': [