From 67fcda2cdecf349dffac8d3b0b013441dc987040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sun, 4 Jun 2017 01:13:57 +0200 Subject: [PATCH] tests: basic tests for AppVM Specifically, check if root volume is updated after template switch. --- qubes/tests/__init__.py | 1 + qubes/tests/vm/__init__.py | 4 ++ qubes/tests/vm/appvm.py | 113 +++++++++++++++++++++++++++++++++++++ rpm_spec/core-dom0.spec | 1 + 4 files changed, 119 insertions(+) create mode 100644 qubes/tests/vm/appvm.py diff --git a/qubes/tests/__init__.py b/qubes/tests/__init__.py index 84628c2d7..a53ca25b7 100644 --- a/qubes/tests/__init__.py +++ b/qubes/tests/__init__.py @@ -966,6 +966,7 @@ def load_tests(loader, tests, pattern): # pylint: disable=unused-argument 'qubes.tests.vm.qubesvm', 'qubes.tests.vm.mix.net', 'qubes.tests.vm.adminvm', + 'qubes.tests.vm.appvm', 'qubes.tests.app', 'qubes.tests.tarwriter', 'qubes.tests.api_admin', diff --git a/qubes/tests/vm/__init__.py b/qubes/tests/vm/__init__.py index b14cd27c4..463389cef 100644 --- a/qubes/tests/vm/__init__.py +++ b/qubes/tests/vm/__init__.py @@ -51,8 +51,12 @@ def get_label(self, label): return l raise KeyError(label) + def get_pool(self, pool): + return self.pools[pool] + def __init__(self): super(TestApp, self).__init__() self.vmm = TestVMM() self.host = TestHost() self.pools = {} + self.domains = {} diff --git a/qubes/tests/vm/appvm.py b/qubes/tests/vm/appvm.py new file mode 100644 index 000000000..4e978d3e1 --- /dev/null +++ b/qubes/tests/vm/appvm.py @@ -0,0 +1,113 @@ +# -*- encoding: utf8 -*- +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2017 Marek Marczykowski-Górecki +# +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, see . + +from unittest import mock + +import qubes.tests +import qubes.tests.vm.qubesvm +import qubes.vm.appvm +import qubes.vm.templatevm + +class TestApp(object): + labels = {1: qubes.Label(1, '0xcc0000', 'red')} + + def __init__(self): + self.domains = {} + +class TestProp(object): + # pylint: disable=too-few-public-methods + __name__ = 'testprop' + +class TestVM(object): + # pylint: disable=too-few-public-methods + app = TestApp() + + def __init__(self, **kwargs): + self.running = False + self.installed_by_rpm = False + for k, v in kwargs.items(): + setattr(self, k, v) + + def is_running(self): + return self.running + +class TC_90_AppVM(qubes.tests.vm.qubesvm.QubesVMTestsMixin, + qubes.tests.QubesTestCase): + def setUp(self): + super().setUp() + self.app.pools['default'] = mock.Mock(**{ + 'init_volume.return_value.pool': 'default'}) + self.app.pools['linux-kernel'] = mock.Mock(**{ + 'init_volume.return_value.pool': 'linux-kernel'}) + self.template = qubes.vm.templatevm.TemplateVM(self.app, None, + qid=1, name=qubes.tests.VMPREFIX + 'template') + self.app.domains[self.template.name] = self.template + self.app.domains[self.template] = self.template + + def get_vm(self, **kwargs): + return qubes.vm.appvm.AppVM(self.app, None, + qid=2, name=qubes.tests.VMPREFIX + 'test', + template=self.template, + **kwargs) + + def test_000_init(self): + self.get_vm() + + def test_001_storage_init(self): + vm = self.get_vm() + self.assertTrue(vm.volume_config['private']['save_on_stop']) + self.assertFalse(vm.volume_config['private']['snap_on_start']) + self.assertIsNone(vm.volume_config['private'].get('source', None)) + + self.assertFalse(vm.volume_config['root']['save_on_stop']) + self.assertTrue(vm.volume_config['root']['snap_on_start']) + self.assertEqual(vm.volume_config['root'].get('source', None), + self.template.volumes['root'].source) + + self.assertFalse( + vm.volume_config['volatile'].get('save_on_stop', False)) + self.assertFalse( + vm.volume_config['volatile'].get('snap_on_start', False)) + self.assertIsNone(vm.volume_config['volatile'].get('source', None)) + + def test_002_storage_template_change(self): + vm = self.get_vm() + # create new mock, so new template will get different volumes + self.app.pools['default'] = mock.Mock(**{ + 'init_volume.return_value.pool': 'default'}) + template2 = qubes.vm.templatevm.TemplateVM(self.app, None, + qid=3, name=qubes.tests.VMPREFIX + 'template2') + self.app.domains[template2.name] = template2 + self.app.domains[template2] = template2 + + vm.template = template2 + self.assertFalse(vm.volume_config['root']['save_on_stop']) + self.assertTrue(vm.volume_config['root']['snap_on_start']) + self.assertNotEqual(vm.volume_config['root'].get('source', None), + self.template.volumes['root'].source) + self.assertEqual(vm.volume_config['root'].get('source', None), + template2.volumes['root'].source) + + def test_003_template_change_running(self): + vm = self.get_vm() + with mock.patch.object(vm, 'get_power_state') as mock_power: + mock_power.return_value = 'Running' + with self.assertRaises(qubes.exc.QubesVMNotHaltedError): + vm.template = self.template diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index 17a1ed0cd..4573836ec 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -318,6 +318,7 @@ fi %{python3_sitelib}/qubes/tests/vm/__init__.py %{python3_sitelib}/qubes/tests/vm/init.py %{python3_sitelib}/qubes/tests/vm/adminvm.py +%{python3_sitelib}/qubes/tests/vm/appvm.py %{python3_sitelib}/qubes/tests/vm/qubesvm.py %dir %{python3_sitelib}/qubes/tests/vm/mix