2020-01-24 16:52:39 +01:00
|
|
|
# -*- encoding: utf-8 -*-
|
2017-06-12 12:22:39 +02:00
|
|
|
#
|
|
|
|
# The Qubes OS Project, http://www.qubes-os.org
|
|
|
|
#
|
|
|
|
# Copyright (C) 2017 Marek Marczykowski-Górecki
|
|
|
|
# <marmarek@invisiblethingslab.com>
|
|
|
|
#
|
2017-10-12 00:11:50 +02:00
|
|
|
# This library is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
|
|
# License as published by the Free Software Foundation; either
|
|
|
|
# version 2.1 of the License, or (at your option) any later version.
|
2017-06-12 12:22:39 +02:00
|
|
|
#
|
2017-10-12 00:11:50 +02:00
|
|
|
# This library is distributed in the hope that it will be useful,
|
2017-06-12 12:22:39 +02:00
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2017-10-12 00:11:50 +02:00
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
# Lesser General Public License for more details.
|
2017-06-12 12:22:39 +02:00
|
|
|
#
|
2017-10-12 00:11:50 +02:00
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
|
|
# License along with this library; if not, see <https://www.gnu.org/licenses/>.
|
2017-06-12 12:22:39 +02:00
|
|
|
|
2020-02-20 14:53:44 +01:00
|
|
|
import os
|
2017-06-12 12:22:39 +02:00
|
|
|
import qubes.ext.core_features
|
2018-10-17 17:37:02 +02:00
|
|
|
import qubes.ext.services
|
2018-07-09 19:42:18 +02:00
|
|
|
import qubes.ext.windows
|
2017-06-12 12:22:39 +02:00
|
|
|
import qubes.tests
|
|
|
|
|
2020-02-20 14:53:44 +01:00
|
|
|
from unittest import mock
|
2017-06-12 12:22:39 +02:00
|
|
|
|
|
|
|
class TC_00_CoreFeatures(qubes.tests.QubesTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
self.ext = qubes.ext.core_features.CoreFeatures()
|
|
|
|
self.vm = mock.MagicMock()
|
|
|
|
self.features = {}
|
|
|
|
self.vm.configure_mock(**{
|
|
|
|
'features.get.side_effect': self.features.get,
|
2020-05-05 17:01:38 +02:00
|
|
|
'features.items.side_effect': self.features.items,
|
|
|
|
'features.__iter__.side_effect': self.features.__iter__,
|
2017-06-12 12:22:39 +02:00
|
|
|
'features.__contains__.side_effect': self.features.__contains__,
|
|
|
|
'features.__setitem__.side_effect': self.features.__setitem__,
|
2020-05-05 17:01:38 +02:00
|
|
|
'features.__delitem__.side_effect': self.features.__delitem__,
|
2017-06-12 12:22:39 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
def test_010_notify_tools(self):
|
|
|
|
del self.vm.template
|
2018-11-11 07:50:36 +01:00
|
|
|
self.loop.run_until_complete(
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'gui': '1',
|
|
|
|
'version': '1',
|
|
|
|
'default-user': 'user',
|
2020-01-24 16:52:39 +01:00
|
|
|
'qrexec': '1',
|
|
|
|
'vmexec': '1'}))
|
|
|
|
self.assertListEqual(self.vm.mock_calls, [
|
2017-06-12 12:22:39 +02:00
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
('features.__contains__', ('qrexec',), {}),
|
|
|
|
('features.__setitem__', ('qrexec', True), {}),
|
|
|
|
('features.__contains__', ('gui',), {}),
|
|
|
|
('features.__setitem__', ('gui', True), {}),
|
2020-01-24 16:52:39 +01:00
|
|
|
('features.__setitem__', ('vmexec', True), {}),
|
2017-06-12 12:22:39 +02:00
|
|
|
('features.get', ('qrexec', False), {}),
|
2018-11-11 07:50:36 +01:00
|
|
|
('fire_event_async', ('template-postinstall',), {}),
|
|
|
|
('fire_event_async().__iter__', (), {}),
|
2017-06-12 12:22:39 +02:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_011_notify_tools_uninstall(self):
|
|
|
|
del self.vm.template
|
2018-11-11 07:50:36 +01:00
|
|
|
self.loop.run_until_complete(
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'gui': '0',
|
|
|
|
'version': '1',
|
|
|
|
'default-user': 'user',
|
2020-01-24 16:52:39 +01:00
|
|
|
'qrexec': '0',
|
|
|
|
'vmexec': '0'}))
|
|
|
|
self.assertListEqual(self.vm.mock_calls, [
|
2017-06-12 12:22:39 +02:00
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
('features.__contains__', ('qrexec',), {}),
|
|
|
|
('features.__setitem__', ('qrexec', False), {}),
|
|
|
|
('features.__contains__', ('gui',), {}),
|
|
|
|
('features.__setitem__', ('gui', False), {}),
|
2020-01-24 16:52:39 +01:00
|
|
|
('features.__setitem__', ('vmexec', False), {}),
|
2017-06-12 12:22:39 +02:00
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_012_notify_tools_uninstall2(self):
|
|
|
|
del self.vm.template
|
2018-11-11 07:50:36 +01:00
|
|
|
self.loop.run_until_complete(
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'version': '1',
|
|
|
|
'default-user': 'user',
|
|
|
|
}))
|
2020-01-24 16:52:39 +01:00
|
|
|
self.assertListEqual(self.vm.mock_calls, [
|
2017-06-12 12:22:39 +02:00
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_013_notify_tools_no_version(self):
|
|
|
|
del self.vm.template
|
2018-11-11 07:50:36 +01:00
|
|
|
self.loop.run_until_complete(
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'qrexec': '1',
|
|
|
|
'gui': '1',
|
|
|
|
'default-user': 'user',
|
|
|
|
}))
|
2020-01-24 16:52:39 +01:00
|
|
|
self.assertListEqual(self.vm.mock_calls, [
|
2017-06-12 12:22:39 +02:00
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
('features.__contains__', ('qrexec',), {}),
|
|
|
|
('features.__setitem__', ('qrexec', True), {}),
|
|
|
|
('features.__contains__', ('gui',), {}),
|
|
|
|
('features.__setitem__', ('gui', True), {}),
|
|
|
|
('features.get', ('qrexec', False), {}),
|
2018-11-11 07:50:36 +01:00
|
|
|
('fire_event_async', ('template-postinstall',), {}),
|
|
|
|
('fire_event_async().__iter__', (), {}),
|
2017-06-12 12:22:39 +02:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_015_notify_tools_invalid_value_qrexec(self):
|
|
|
|
del self.vm.template
|
2018-11-11 07:50:36 +01:00
|
|
|
self.loop.run_until_complete(
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'version': '1',
|
|
|
|
'qrexec': 'invalid',
|
|
|
|
'gui': '1',
|
|
|
|
'default-user': 'user',
|
|
|
|
}))
|
2017-06-12 12:22:39 +02:00
|
|
|
self.assertEqual(self.vm.mock_calls, [
|
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
('features.__contains__', ('gui',), {}),
|
|
|
|
('features.__setitem__', ('gui', True), {}),
|
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_016_notify_tools_invalid_value_gui(self):
|
|
|
|
del self.vm.template
|
2018-11-11 07:50:36 +01:00
|
|
|
self.loop.run_until_complete(
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'version': '1',
|
|
|
|
'qrexec': '1',
|
|
|
|
'gui': 'invalid',
|
|
|
|
'default-user': 'user',
|
|
|
|
}))
|
2020-01-24 16:52:39 +01:00
|
|
|
self.assertListEqual(self.vm.mock_calls, [
|
2017-06-12 12:22:39 +02:00
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
('features.__contains__', ('qrexec',), {}),
|
|
|
|
('features.__setitem__', ('qrexec', True), {}),
|
|
|
|
('features.get', ('qrexec', False), {}),
|
2018-11-11 07:50:36 +01:00
|
|
|
('fire_event_async', ('template-postinstall',), {}),
|
|
|
|
('fire_event_async().__iter__', (), {}),
|
2017-06-12 12:22:39 +02:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_017_notify_tools_template_based(self):
|
2018-11-11 07:50:36 +01:00
|
|
|
self.loop.run_until_complete(
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'version': '1',
|
|
|
|
'qrexec': '1',
|
|
|
|
'gui': '1',
|
|
|
|
'default-user': 'user',
|
|
|
|
}))
|
2017-06-12 12:22:39 +02:00
|
|
|
self.assertEqual(self.vm.mock_calls, [
|
|
|
|
('template.__bool__', (), {}),
|
|
|
|
('log.warning', ('Ignoring qubes.NotifyTools for template-based '
|
|
|
|
'VM',), {})
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_018_notify_tools_already_installed(self):
|
|
|
|
self.features['qrexec'] = True
|
|
|
|
self.features['gui'] = True
|
|
|
|
del self.vm.template
|
2018-11-11 07:50:36 +01:00
|
|
|
self.loop.run_until_complete(
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'gui': '1',
|
|
|
|
'version': '1',
|
|
|
|
'default-user': 'user',
|
|
|
|
'qrexec': '1'}))
|
2020-01-24 16:52:39 +01:00
|
|
|
self.assertListEqual(self.vm.mock_calls, [
|
2017-06-12 12:22:39 +02:00
|
|
|
('features.get', ('qrexec', False), {}),
|
|
|
|
('features.__contains__', ('qrexec',), {}),
|
|
|
|
('features.__contains__', ('gui',), {}),
|
|
|
|
])
|
2018-07-09 19:42:18 +02:00
|
|
|
|
2020-05-05 17:01:38 +02:00
|
|
|
def test_100_servicevm_feature(self):
|
|
|
|
self.vm.provides_network = True
|
|
|
|
self.ext.set_servicevm_feature(self.vm)
|
|
|
|
self.assertEqual(self.features['servicevm'], 1)
|
|
|
|
|
|
|
|
self.vm.provides_network = False
|
|
|
|
self.ext.set_servicevm_feature(self.vm)
|
|
|
|
self.assertNotIn('servicevm', self.features)
|
|
|
|
|
|
|
|
|
2018-07-09 19:42:18 +02:00
|
|
|
class TC_10_WindowsFeatures(qubes.tests.QubesTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
self.ext = qubes.ext.windows.WindowsFeatures()
|
|
|
|
self.vm = mock.MagicMock()
|
|
|
|
self.features = {}
|
|
|
|
self.vm.configure_mock(**{
|
|
|
|
'features.get.side_effect': self.features.get,
|
|
|
|
'features.__contains__.side_effect': self.features.__contains__,
|
|
|
|
'features.__setitem__.side_effect': self.features.__setitem__,
|
|
|
|
})
|
|
|
|
|
|
|
|
def test_000_notify_tools_full(self):
|
|
|
|
del self.vm.template
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'gui': '1',
|
|
|
|
'version': '1',
|
|
|
|
'default-user': 'user',
|
|
|
|
'qrexec': '1',
|
|
|
|
'os': 'Windows'})
|
|
|
|
self.assertEqual(self.vm.mock_calls, [
|
|
|
|
('features.__setitem__', ('os', 'Windows'), {}),
|
|
|
|
('features.__setitem__', ('rpc-clipboard', True), {}),
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_001_notify_tools_no_qrexec(self):
|
|
|
|
del self.vm.template
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'gui': '1',
|
|
|
|
'version': '1',
|
|
|
|
'default-user': 'user',
|
|
|
|
'qrexec': '0',
|
|
|
|
'os': 'Windows'})
|
|
|
|
self.assertEqual(self.vm.mock_calls, [
|
|
|
|
('features.__setitem__', ('os', 'Windows'), {}),
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_002_notify_tools_other_os(self):
|
|
|
|
del self.vm.template
|
|
|
|
self.ext.qubes_features_request(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'gui': '1',
|
|
|
|
'version': '1',
|
|
|
|
'default-user': 'user',
|
|
|
|
'qrexec': '1',
|
2018-10-23 23:29:23 +02:00
|
|
|
'os': 'other'})
|
2018-07-09 19:42:18 +02:00
|
|
|
self.assertEqual(self.vm.mock_calls, [])
|
2018-10-17 17:37:02 +02:00
|
|
|
|
|
|
|
class TC_20_Services(qubes.tests.QubesTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
self.ext = qubes.ext.services.ServicesExtension()
|
|
|
|
self.features = {}
|
2020-02-20 14:53:44 +01:00
|
|
|
specs = {
|
2018-10-17 17:37:02 +02:00
|
|
|
'features.get.side_effect': self.features.get,
|
|
|
|
'features.items.side_effect': self.features.items,
|
|
|
|
'features.__iter__.side_effect': self.features.__iter__,
|
|
|
|
'features.__contains__.side_effect': self.features.__contains__,
|
|
|
|
'features.__setitem__.side_effect': self.features.__setitem__,
|
|
|
|
'features.__delitem__.side_effect': self.features.__delitem__,
|
2020-02-20 14:53:44 +01:00
|
|
|
}
|
|
|
|
vmspecs = {**specs, **{
|
|
|
|
'template': None,
|
|
|
|
'maxmem': 1024,
|
|
|
|
'is_running.return_value': True,
|
|
|
|
}}
|
|
|
|
dom0specs = {**specs, **{
|
|
|
|
'name': "dom0",
|
|
|
|
}}
|
|
|
|
self.vm = mock.MagicMock()
|
|
|
|
self.vm.configure_mock(**vmspecs)
|
|
|
|
self.dom0 = mock.MagicMock()
|
|
|
|
self.dom0.configure_mock(**dom0specs)
|
2018-10-17 17:37:02 +02:00
|
|
|
|
|
|
|
def test_000_write_to_qdb(self):
|
|
|
|
self.features['service.test1'] = '1'
|
|
|
|
self.features['service.test2'] = ''
|
|
|
|
|
|
|
|
self.ext.on_domain_qdb_create(self.vm, 'domain-qdb-create')
|
|
|
|
self.assertEqual(sorted(self.vm.untrusted_qdb.mock_calls), [
|
Use maxmem=0 to disable qmemman, add more automation to it
Use maxmem=0 for disabling dynamic memory balance, instead of cryptic
service.meminfo-writer feature. Under the hood, meminfo-writer service
is also set based on maxmem property (directly in qubesdb, not
vm.features dict).
Having this as a property (not "feature"), allow to have sensible
handling of default value. Specifically, disable it automatically if
otherwise it would crash a VM. This is the case for:
- domain with PCI devices (PoD is not supported by Xen then)
- domain without balloon driver and/or meminfo-writer service
The check for the latter is heuristic (assume presence of 'qrexec' also
can indicate balloon driver support), but it is true for currently
supported systems.
This also allows more reliable control of libvirt config: do not set
memory != maxmem, unless qmemman is enabled.
memory != maxmem only makes sense if qmemman for given domain is
enabled. Besides wasting some domain resources for extra page tables
etc, for HVM domains this is harmful, because maxmem-memory difference
is made of Popupate-on-Demand pool, which - when depleted - will kill
the domain. This means domain without balloon driver will die as soon
as will try to use more than initial memory - but without balloon driver
it sees maxmem memory and doesn't know about the lower limit.
Fixes QubesOS/qubes-issues#4135
2018-11-03 05:13:23 +01:00
|
|
|
('write', ('/qubes-service/meminfo-writer', '1'), {}),
|
2018-10-17 17:37:02 +02:00
|
|
|
('write', ('/qubes-service/test1', '1'), {}),
|
|
|
|
('write', ('/qubes-service/test2', '0'), {}),
|
|
|
|
])
|
|
|
|
|
|
|
|
def test_001_feature_set(self):
|
|
|
|
self.ext.on_domain_feature_set(self.vm,
|
|
|
|
'feature-set:service.test_no_oldvalue',
|
|
|
|
'service.test_no_oldvalue', '1')
|
|
|
|
self.ext.on_domain_feature_set(self.vm,
|
|
|
|
'feature-set:service.test_oldvalue',
|
|
|
|
'service.test_oldvalue', '1', '')
|
|
|
|
self.ext.on_domain_feature_set(self.vm,
|
|
|
|
'feature-set:service.test_disable',
|
|
|
|
'service.test_disable', '', '1')
|
|
|
|
self.ext.on_domain_feature_set(self.vm,
|
|
|
|
'feature-set:service.test_disable_no_oldvalue',
|
|
|
|
'service.test_disable_no_oldvalue', '')
|
|
|
|
|
|
|
|
self.assertEqual(sorted(self.vm.untrusted_qdb.mock_calls), sorted([
|
|
|
|
('write', ('/qubes-service/test_no_oldvalue', '1'), {}),
|
|
|
|
('write', ('/qubes-service/test_oldvalue', '1'), {}),
|
|
|
|
('write', ('/qubes-service/test_disable', '0'), {}),
|
|
|
|
('write', ('/qubes-service/test_disable_no_oldvalue', '0'), {}),
|
|
|
|
]))
|
|
|
|
|
|
|
|
def test_002_feature_delete(self):
|
|
|
|
self.ext.on_domain_feature_delete(self.vm,
|
|
|
|
'feature-delete:service.test3', 'service.test3')
|
|
|
|
self.assertEqual(sorted(self.vm.untrusted_qdb.mock_calls), [
|
|
|
|
('rm', ('/qubes-service/test3',), {}),
|
|
|
|
])
|
2018-10-18 05:44:08 +02:00
|
|
|
|
|
|
|
def test_010_supported_services(self):
|
|
|
|
self.ext.supported_services(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'supported-service.test1': '1', # ok
|
|
|
|
'supported-service.test2': '0', # ignored
|
|
|
|
'supported-service.test3': 'some text', # ignored
|
|
|
|
'no-service': '1', # ignored
|
|
|
|
})
|
|
|
|
self.assertEqual(self.features, {
|
|
|
|
'supported-service.test1': True,
|
|
|
|
})
|
|
|
|
|
|
|
|
def test_011_supported_services_add(self):
|
|
|
|
self.features['supported-service.test1'] = '1'
|
|
|
|
self.ext.supported_services(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'supported-service.test1': '1', # ok
|
|
|
|
'supported-service.test2': '1', # ok
|
|
|
|
})
|
|
|
|
# also check if existing one is untouched
|
|
|
|
self.assertEqual(self.features, {
|
|
|
|
'supported-service.test1': '1',
|
|
|
|
'supported-service.test2': True,
|
|
|
|
})
|
|
|
|
|
|
|
|
def test_012_supported_services_remove(self):
|
|
|
|
self.features['supported-service.test1'] = '1'
|
|
|
|
self.ext.supported_services(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'supported-service.test2': '1', # ok
|
|
|
|
})
|
|
|
|
self.assertEqual(self.features, {
|
|
|
|
'supported-service.test2': True,
|
|
|
|
})
|
2020-02-20 14:53:44 +01:00
|
|
|
|
|
|
|
def test_013_feature_set_dom0(self):
|
|
|
|
self.test_base_dir = '/tmp/qubes-test-dir'
|
|
|
|
self.base_dir_patch = mock.patch.dict(
|
|
|
|
qubes.config.system_path, {'dom0_services_dir': self.test_base_dir})
|
|
|
|
self.base_dir_patch.start()
|
2020-03-08 10:01:26 +01:00
|
|
|
self.addCleanup(self.base_dir_patch.stop)
|
2020-02-20 14:53:44 +01:00
|
|
|
service = 'guivm-gui-agent'
|
|
|
|
service_path = self.test_base_dir + '/' + service
|
|
|
|
|
|
|
|
self.ext.on_domain_feature_set(
|
|
|
|
self.dom0,
|
|
|
|
'feature-set:service.service.guivm-gui-agent',
|
|
|
|
'service.guivm-gui-agent', '1')
|
|
|
|
self.assertEqual(os.path.exists(service_path), True)
|
|
|
|
|
|
|
|
def test_014_feature_delete_dom0(self):
|
|
|
|
self.test_base_dir = '/tmp/qubes-test-dir'
|
|
|
|
self.base_dir_patch = mock.patch.dict(
|
|
|
|
qubes.config.system_path, {'dom0_services_dir': self.test_base_dir})
|
|
|
|
self.base_dir_patch.start()
|
2020-03-08 10:01:26 +01:00
|
|
|
self.addCleanup(self.base_dir_patch.stop)
|
2020-02-20 14:53:44 +01:00
|
|
|
service = 'guivm-gui-agent'
|
|
|
|
service_path = self.test_base_dir + '/' + service
|
|
|
|
|
|
|
|
self.ext.on_domain_feature_set(
|
|
|
|
self.dom0,
|
|
|
|
'feature-set:service.service.guivm-gui-agent',
|
|
|
|
'service.guivm-gui-agent', '1')
|
|
|
|
|
|
|
|
self.ext.on_domain_feature_delete(
|
|
|
|
self.dom0,
|
|
|
|
'feature-delete:service.service.guivm-gui-agent',
|
|
|
|
'service.guivm-gui-agent')
|
|
|
|
|
2020-03-08 10:01:26 +01:00
|
|
|
self.assertEqual(os.path.exists(service_path), False)
|
|
|
|
|
|
|
|
def test_014_feature_set_empty_value_dom0(self):
|
|
|
|
self.test_base_dir = '/tmp/qubes-test-dir'
|
|
|
|
self.base_dir_patch = mock.patch.dict(
|
|
|
|
qubes.config.system_path, {'dom0_services_dir': self.test_base_dir})
|
|
|
|
self.base_dir_patch.start()
|
|
|
|
self.addCleanup(self.base_dir_patch.stop)
|
|
|
|
service = 'guivm-gui-agent'
|
|
|
|
service_path = self.test_base_dir + '/' + service
|
|
|
|
|
|
|
|
self.ext.on_domain_feature_set(
|
|
|
|
self.dom0,
|
|
|
|
'feature-set:service.service.guivm-gui-agent',
|
|
|
|
'service.guivm-gui-agent', '')
|
|
|
|
|
|
|
|
self.assertEqual(os.path.exists(service_path), False)
|
2020-09-23 00:57:30 +02:00
|
|
|
|
|
|
|
class TC_30_SupportedFeatures(qubes.tests.QubesTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
self.ext = qubes.ext.supported_features.SupportedFeaturesExtension()
|
|
|
|
self.features = {}
|
|
|
|
specs = {
|
|
|
|
'features.get.side_effect': self.features.get,
|
|
|
|
'features.items.side_effect': self.features.items,
|
|
|
|
'features.__iter__.side_effect': self.features.__iter__,
|
|
|
|
'features.__contains__.side_effect': self.features.__contains__,
|
|
|
|
'features.__setitem__.side_effect': self.features.__setitem__,
|
|
|
|
'features.__delitem__.side_effect': self.features.__delitem__,
|
|
|
|
}
|
|
|
|
vmspecs = {**specs, **{
|
|
|
|
'template': None,
|
|
|
|
'maxmem': 1024,
|
|
|
|
'is_running.return_value': True,
|
|
|
|
}}
|
|
|
|
dom0specs = {**specs, **{
|
|
|
|
'name': "dom0",
|
|
|
|
}}
|
|
|
|
self.vm = mock.MagicMock()
|
|
|
|
self.vm.configure_mock(**vmspecs)
|
|
|
|
self.dom0 = mock.MagicMock()
|
|
|
|
self.dom0.configure_mock(**dom0specs)
|
|
|
|
|
|
|
|
def test_010_supported_features(self):
|
|
|
|
self.ext.supported_features(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'supported-feature.test1': '1', # ok
|
|
|
|
'supported-feature.test2': '0', # ignored
|
|
|
|
'supported-feature.test3': 'some text', # ignored
|
|
|
|
'no-feature': '1', # ignored
|
|
|
|
})
|
|
|
|
self.assertEqual(self.features, {
|
|
|
|
'supported-feature.test1': True,
|
|
|
|
})
|
|
|
|
|
|
|
|
def test_011_supported_features_add(self):
|
|
|
|
self.features['supported-feature.test1'] = '1'
|
|
|
|
self.ext.supported_features(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'supported-feature.test1': '1', # ok
|
|
|
|
'supported-feature.test2': '1', # ok
|
|
|
|
})
|
|
|
|
# also check if existing one is untouched
|
|
|
|
self.assertEqual(self.features, {
|
|
|
|
'supported-feature.test1': '1',
|
|
|
|
'supported-feature.test2': True,
|
|
|
|
})
|
|
|
|
|
|
|
|
def test_012_supported_features_remove(self):
|
|
|
|
self.features['supported-feature.test1'] = '1'
|
|
|
|
self.ext.supported_features(self.vm, 'features-request',
|
|
|
|
untrusted_features={
|
|
|
|
'supported-feature.test2': '1', # ok
|
|
|
|
})
|
|
|
|
self.assertEqual(self.features, {
|
|
|
|
'supported-feature.test2': True,
|
|
|
|
})
|