qvm_device.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. # pylint: disable=protected-access
  2. #
  3. # The Qubes OS Project, https://www.qubes-os.org/
  4. #
  5. # Copyright (C) 2015 Marek Marczykowski-Górecki
  6. # <marmarek@invisiblethingslab.com>
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program 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
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License along
  19. # with this program; if not, write to the Free Software Foundation, Inc.,
  20. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. #
  22. ''' Tests for the `qvm-device` tool. '''
  23. import qubes
  24. import qubes.devices
  25. import qubes.tools.qvm_device
  26. import qubes.tests
  27. import qubes.tests.devices
  28. import qubes.tests.tools
  29. class TestNamespace(object):
  30. ''' A mock object for `argparse.Namespace`.
  31. ''' # pylint: disable=too-few-public-methods
  32. def __init__(self, app, domains=None, device=None):
  33. super(TestNamespace, self).__init__()
  34. self.app = app
  35. self.devclass = 'testclass'
  36. self.persistent = True
  37. if domains:
  38. self.domains = domains
  39. if device:
  40. self.device = device
  41. self.device_assignment = qubes.devices.DeviceAssignment(
  42. backend_domain=self.device.backend_domain,
  43. ident=self.device.ident, persistent=self.persistent)
  44. class TC_00_Actions(qubes.tests.QubesTestCase):
  45. ''' Tests the output logic of the qvm-device tool '''
  46. def setUp(self):
  47. super(TC_00_Actions, self).setUp()
  48. self.app = qubes.tests.devices.TestApp()
  49. def save():
  50. ''' A mock method for simulating a successful save '''
  51. return True
  52. self.app.save = save
  53. self.vm1 = qubes.tests.devices.TestVM(self.app, 'vm1')
  54. self.vm2 = qubes.tests.devices.TestVM(self.app, 'vm2')
  55. self.device = self.vm2.device
  56. def test_000_list_all(self):
  57. ''' List all exposed vm devices. No devices are attached to other
  58. domains.
  59. '''
  60. args = TestNamespace(self.app)
  61. with qubes.tests.tools.StdoutBuffer() as buf:
  62. qubes.tools.qvm_device.list_devices(args)
  63. self.assertEqual(
  64. [x.rstrip() for x in buf.getvalue().splitlines()],
  65. ['vm1:testdev Description',
  66. 'vm2:testdev Description']
  67. )
  68. def test_001_list_persistent_attach(self):
  69. ''' Attach the device exposed by the `vm2` to the `vm1` persistently.
  70. '''
  71. args = TestNamespace(self.app, [self.vm1])
  72. # simulate attach
  73. assignment = qubes.devices.DeviceAssignment(backend_domain=self.vm2,
  74. ident=self.device.ident, persistent=True, frontend_domain=self.vm1)
  75. self.vm2.device.frontend_domain = self.vm1
  76. self.vm1.devices['testclass']._set.add(assignment)
  77. with qubes.tests.tools.StdoutBuffer() as buf:
  78. qubes.tools.qvm_device.list_devices(args)
  79. self.assertEqual(
  80. buf.getvalue(),
  81. 'vm1:testdev Description\n'
  82. 'vm2:testdev Description vm1 vm1\n'
  83. )
  84. def test_002_list_list_temp_attach(self):
  85. ''' Attach the device exposed by the `vm2` to the `vm1`
  86. non-persistently.
  87. '''
  88. args = TestNamespace(self.app, [self.vm1])
  89. # simulate attach
  90. assignment = qubes.devices.DeviceAssignment(backend_domain=self.vm2,
  91. ident=self.device.ident, persistent=True, frontend_domain=self.vm1)
  92. self.vm2.device.frontend_domain = self.vm1
  93. self.vm1.devices['testclass']._set.add(assignment)
  94. with qubes.tests.tools.StdoutBuffer() as buf:
  95. qubes.tools.qvm_device.list_devices(args)
  96. self.assertEqual(buf.getvalue(),
  97. 'vm1:testdev Description\n'
  98. 'vm2:testdev Description vm1 vm1\n')
  99. def test_010_attach(self):
  100. ''' Test attach action '''
  101. args = TestNamespace(
  102. self.app,
  103. [self.vm1],
  104. self.device
  105. )
  106. qubes.tools.qvm_device.attach_device(args)
  107. self.assertEventFired(self.vm1,
  108. 'device-attach:testclass', kwargs={'device': self.device})
  109. self.assertEventNotFired(self.vm2,
  110. 'device-attach:testclass', kwargs={'device': self.device})
  111. def test_011_double_attach(self):
  112. ''' Double attach should not be possible '''
  113. args = TestNamespace(
  114. self.app,
  115. [self.vm1],
  116. self.device
  117. )
  118. qubes.tools.qvm_device.attach_device(args)
  119. with self.assertRaises(qubes.exc.QubesException):
  120. qubes.tools.qvm_device.attach_device(args)
  121. def test_020_detach(self):
  122. ''' Test detach action '''
  123. args = TestNamespace(
  124. self.app,
  125. [self.vm1],
  126. self.device
  127. )
  128. # simulate attach
  129. self.vm2.device.frontend_domain = self.vm1
  130. args.device_assignment.frontend_domain = self.vm1
  131. self.vm1.devices['testclass']._set.add(args.device_assignment)
  132. qubes.tools.qvm_device.detach_device(args)
  133. def test_021_detach_not_attached(self):
  134. ''' Invalid detach action should not be possible '''
  135. args = TestNamespace(
  136. self.app,
  137. [self.vm1],
  138. self.device
  139. )
  140. with self.assertRaises(qubes.exc.QubesException):
  141. qubes.tools.qvm_device.detach_device(args)