init.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. # pylint: disable=protected-access
  2. #
  3. # The Qubes OS Project, https://www.qubes-os.org/
  4. #
  5. # Copyright (C) 2014-2015 Joanna Rutkowska <joanna@invisiblethingslab.com>
  6. # Copyright (C) 2014-2015 Wojtek Porczyk <woju@invisiblethingslab.com>
  7. #
  8. # This library is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU Lesser General Public
  10. # License as published by the Free Software Foundation; either
  11. # version 2.1 of the License, or (at your option) any later version.
  12. #
  13. # This library is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. # Lesser General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU Lesser General Public
  19. # License along with this library; if not, see <https://www.gnu.org/licenses/>.
  20. #
  21. import lxml.etree
  22. import qubes
  23. import qubes.events
  24. import qubes.vm
  25. import qubes.tests
  26. class TestVMM(object):
  27. def __init__(self):
  28. super(TestVMM, self).__init__()
  29. self.offline_mode = True
  30. class TestApp(object):
  31. def __init__(self):
  32. super(TestApp, self).__init__()
  33. self.domains = {}
  34. self.vmm = TestVMM()
  35. class TestVM(qubes.vm.BaseVM):
  36. qid = qubes.property('qid', type=int)
  37. name = qubes.property('name')
  38. testprop = qubes.property('testprop')
  39. testlabel = qubes.property('testlabel')
  40. defaultprop = qubes.property('defaultprop', default='defaultvalue')
  41. class TC_10_BaseVM(qubes.tests.QubesTestCase):
  42. def setUp(self):
  43. super().setUp()
  44. self.xml = lxml.etree.XML('''
  45. <qubes version="3"> <!-- xmlns="https://qubes-os.org/QubesXML/1" -->
  46. <labels>
  47. <label id="label-1" color="#cc0000">red</label>
  48. </labels>
  49. <domains>
  50. <domain id="domain-1" class="TestVM">
  51. <properties>
  52. <property name="qid">1</property>
  53. <property name="name">domain1</property>
  54. <property name="testprop">testvalue</property>
  55. <property name="testlabel" ref="label-1" />
  56. </properties>
  57. <tags>
  58. <tag name="testtag"/>
  59. </tags>
  60. <features>
  61. <feature name="testfeature_empty"></feature>
  62. <feature name="testfeature_aqq">aqq</feature>
  63. </features>
  64. <devices class="pci">
  65. <device backend-domain="domain1" id="00_11.22">
  66. <option name="no-strict-reset">True</option>
  67. </device>
  68. </devices>
  69. <devices class="usb" />
  70. <devices class="audio-in" />
  71. <devices class="firewire" />
  72. <devices class="i2c" />
  73. <devices class="isa" />
  74. </domain>
  75. </domains>
  76. </qubes>
  77. ''')
  78. def test_000_load(self):
  79. node = self.xml.xpath('//domain')[0]
  80. vm = TestVM(TestApp(), node)
  81. vm.app.domains['domain1'] = vm
  82. vm.load_properties(load_stage=None)
  83. vm.load_extras()
  84. self.assertEqual(vm.qid, 1)
  85. self.assertEqual(vm.testprop, 'testvalue')
  86. self.assertEqual(vm.testprop, 'testvalue')
  87. self.assertEqual(vm.testlabel, 'label-1')
  88. self.assertEqual(vm.defaultprop, 'defaultvalue')
  89. self.assertEqual(vm.tags, {'testtag'})
  90. self.assertEqual(vm.features, {
  91. 'testfeature_empty': '',
  92. 'testfeature_aqq': 'aqq',
  93. })
  94. self.assertCountEqual(vm.devices.keys(), ('pci',))
  95. self.assertCountEqual(list(vm.devices['pci'].persistent()),
  96. [qubes.ext.pci.PCIDevice(vm, '00_11.22')])
  97. assignments = list(vm.devices['pci'].assignments())
  98. self.assertEqual(len(assignments), 1)
  99. self.assertEqual(assignments[0].options, {'no-strict-reset': 'True'})
  100. self.assertEqual(assignments[0].persistent, True)
  101. self.assertXMLIsValid(vm.__xml__(), 'domain.rng')
  102. def test_001_nxproperty(self):
  103. xml = lxml.etree.XML('''
  104. <qubes version="3">
  105. <domains>
  106. <domain id="domain-1" class="TestVM">
  107. <properties>
  108. <property name="qid">1</property>
  109. <property name="name">domain1</property>
  110. <property name="nxproperty">nxvalue</property>
  111. </properties>
  112. </domain>
  113. </domains>
  114. </qubes>
  115. ''')
  116. node = xml.xpath('//domain')[0]
  117. with self.assertRaises(TypeError):
  118. TestVM(None, node)
  119. def test_002_save_nxproperty(self):
  120. vm = TestVM(None, None, qid=1, name='testvm')
  121. vm.nxproperty = 'value'
  122. xml = vm.__xml__()
  123. self.assertNotIn('nxproperty', xml)
  124. class TC_20_Tags(qubes.tests.QubesTestCase):
  125. def setUp(self):
  126. super(TC_20_Tags, self).setUp()
  127. self.vm = qubes.tests.TestEmitter()
  128. self.tags = qubes.vm.Tags(self.vm)
  129. def test_000_add(self):
  130. self.tags.add('testtag')
  131. self.assertEventFired(self.vm, 'domain-tag-add:testtag',
  132. kwargs={'tag': 'testtag'})
  133. def test_001_add_existing(self):
  134. self.tags.add('testtag')
  135. self.vm.fired_events.clear()
  136. self.tags.add('testtag')
  137. self.assertEventNotFired(self.vm, 'domain-tag-add:testtag')
  138. def test_002_remove(self):
  139. self.tags.add('testtag')
  140. self.vm.fired_events.clear()
  141. self.tags.remove('testtag')
  142. self.assertEventFired(self.vm, 'domain-tag-delete:testtag',
  143. kwargs={'tag': 'testtag'})
  144. def test_003_remove_not_present(self):
  145. with self.assertRaises(KeyError):
  146. self.tags.remove('testtag')
  147. self.assertEventNotFired(self.vm, 'domain-tag-delete:testtag')
  148. def test_004_discard_not_present(self):
  149. with self.assertNotRaises(KeyError):
  150. self.tags.discard('testtag')
  151. self.assertEventNotFired(self.vm, 'domain-tag-delete:testtag')
  152. def test_005_discard_present(self):
  153. self.tags.add('testtag')
  154. with self.assertNotRaises(KeyError):
  155. self.tags.discard('testtag')
  156. self.assertEventFired(self.vm, 'domain-tag-delete:testtag',
  157. kwargs={'tag': 'testtag'})
  158. def test_006_clear(self):
  159. self.tags.add('testtag')
  160. self.tags.add('testtag2')
  161. self.vm.fired_events.clear()
  162. self.tags.clear()
  163. self.assertEventFired(self.vm, 'domain-tag-delete:testtag',
  164. kwargs={'tag': 'testtag'})
  165. self.assertEventFired(self.vm, 'domain-tag-delete:testtag2',
  166. kwargs={'tag': 'testtag2'})
  167. def test_007_update(self):
  168. self.tags.add('testtag')
  169. self.tags.add('testtag2')
  170. self.vm.fired_events.clear()
  171. self.tags.update(('testtag2', 'testtag3'))
  172. self.assertEventFired(self.vm, 'domain-tag-add:testtag3',
  173. kwargs={'tag': 'testtag3'})
  174. self.assertEventNotFired(self.vm, 'domain-tag-add:testtag2',
  175. kwargs={'tag': 'testtag2'})
  176. class TC_21_Features(qubes.tests.QubesTestCase):
  177. def setUp(self):
  178. super(TC_21_Features, self).setUp()
  179. self.vm = qubes.tests.TestEmitter()
  180. self.features = qubes.features.Features(self.vm)
  181. def test_000_set(self):
  182. self.features['testfeature'] = 'value'
  183. self.assertEventFired(self.vm, 'domain-feature-pre-set:testfeature',
  184. kwargs={'feature': 'testfeature', 'value': 'value'})
  185. self.assertEventFired(self.vm, 'domain-feature-set:testfeature',
  186. kwargs={'feature': 'testfeature', 'value': 'value'})
  187. def test_001_set_existing(self):
  188. self.features['test'] = 'oldvalue'
  189. self.vm.fired_events.clear()
  190. self.features['test'] = 'value'
  191. self.assertEventFired(self.vm, 'domain-feature-set:test',
  192. kwargs={'feature': 'test', 'value': 'value', 'oldvalue':
  193. 'oldvalue'})
  194. def test_002_unset(self):
  195. self.features['test'] = 'value'
  196. self.vm.fired_events.clear()
  197. del self.features['test']
  198. self.assertEventFired(self.vm, 'domain-feature-delete:test',
  199. kwargs={'feature': 'test'})
  200. def test_003_unset_not_present(self):
  201. with self.assertRaises(KeyError):
  202. del self.features['test']
  203. self.assertEventNotFired(self.vm, 'domain-feature-delete')
  204. self.assertEventNotFired(self.vm, 'domain-feature-delete:test')
  205. def test_004_set_bool_true(self):
  206. self.features['test'] = True
  207. self.assertTrue(self.features['test'])
  208. self.assertEventFired(self.vm, 'domain-feature-set:test',
  209. kwargs={'feature': 'test', 'value': '1'})
  210. def test_005_set_bool_false(self):
  211. self.features['test'] = False
  212. self.assertFalse(self.features['test'])
  213. self.assertEventFired(self.vm, 'domain-feature-set:test',
  214. kwargs={'feature': 'test', 'value': ''})
  215. def test_006_set_int(self):
  216. self.features['test'] = 123
  217. self.assertEventFired(self.vm, 'domain-feature-set:test',
  218. kwargs={'feature': 'test', 'value': '123'})
  219. def test_007_clear(self):
  220. self.features['test'] = 'value1'
  221. self.features['test2'] = 'value2'
  222. self.vm.fired_events.clear()
  223. self.features.clear()
  224. self.assertEventFired(self.vm, 'domain-feature-pre-delete:test',
  225. kwargs={'feature': 'test'})
  226. self.assertEventFired(self.vm, 'domain-feature-delete:test',
  227. kwargs={'feature': 'test'})
  228. self.assertEventFired(self.vm, 'domain-feature-pre-delete:test2',
  229. kwargs={'feature': 'test2'})
  230. self.assertEventFired(self.vm, 'domain-feature-delete:test2',
  231. kwargs={'feature': 'test2'})
  232. def test_008_update(self):
  233. self.features['test'] = 'value'
  234. self.features['test2'] = 'value2'
  235. self.vm.fired_events.clear()
  236. self.features.update({'test2': 'value3', 'test3': 'value4'})
  237. self.assertEqual(self.features['test2'], 'value3')
  238. self.assertEqual(self.features['test3'], 'value4')
  239. self.assertEqual(self.features['test'], 'value')
  240. self.assertEventFired(self.vm, 'domain-feature-set:test2',
  241. kwargs={'feature': 'test2', 'value': 'value3',
  242. 'oldvalue': 'value2'})
  243. self.assertEventFired(self.vm, 'domain-feature-set:test3',
  244. kwargs={'feature': 'test3', 'value': 'value4'})