__init__.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #!/usr/bin/python -O
  2. import collections
  3. import unittest
  4. import qubes.config
  5. import qubes.events
  6. #: :py:obj:`True` if running in dom0, :py:obj:`False` otherwise
  7. in_dom0 = False
  8. try:
  9. import libvirt
  10. libvirt.openReadOnly(qubes.config.defaults['libvirt_uri']).close()
  11. in_dom0 = True
  12. del libvirt
  13. except libvirt.libvirtError:
  14. pass
  15. def skipUnlessDom0(test_item):
  16. '''Decorator that skips test outside dom0.
  17. Some tests (especially integration tests) have to be run in more or less
  18. working dom0. This is checked by connecting to libvirt.
  19. '''
  20. return unittest.skipUnless(in_dom0, 'outside dom0')(test_item)
  21. class TestEmitter(qubes.events.Emitter):
  22. '''Dummy event emitter which records events fired on it.
  23. Events are counted in :py:attr:`fired_events` attribute, which is
  24. :py:class:`collections.Counter` instance. For each event, ``(event, args,
  25. kwargs)`` object is counted. *event* is event name (a string), *args* is
  26. tuple with positional arguments and *kwargs* is sorted tuple of items from
  27. keyword arguments.
  28. >>> emitter = TestEmitter()
  29. >>> emitter.fired_events
  30. Counter()
  31. >>> emitter.fire_event('event', 1, 2, 3, spam='eggs', foo='bar')
  32. >>> emitter.fired_events
  33. Counter({('event', (1, 2, 3), (('foo', 'bar'), ('spam', 'eggs'))): 1})
  34. '''
  35. def __init__(self, *args, **kwargs):
  36. super(TestEmitter, self).__init__(*args, **kwargs)
  37. #: :py:class:`collections.Counter` instance
  38. self.fired_events = collections.Counter()
  39. def fire_event(self, event, *args, **kwargs):
  40. super(TestEmitter, self).fire_event(event, *args, **kwargs)
  41. self.fired_events[(event, args, tuple(sorted(kwargs.items())))] += 1
  42. def fire_event_pre(self, event, *args, **kwargs):
  43. super(TestEmitter, self).fire_event_pre(event, *args, **kwargs)
  44. self.fired_events[(event, args, tuple(sorted(kwargs.items())))] += 1
  45. class QubesTestCase(unittest.TestCase):
  46. '''Base class for Qubes unit tests.
  47. '''
  48. def __str__(self):
  49. return '{}/{}/{}'.format(
  50. '.'.join(self.__class__.__module__.split('.')[2:]),
  51. self.__class__.__name__,
  52. self._testMethodName)
  53. def assertEventFired(self, emitter, event, args=[], kwargs=[]):
  54. '''Check whether event was fired on given emitter and fail if it did
  55. not.
  56. :param emitter: emitter which is being checked
  57. :type emitter: :py:class:`TestEmitter`
  58. :param str event: event identifier
  59. :param list args: when given, all items must appear in args passed to event
  60. :param list kwargs: when given, all items must appear in kwargs passed to event
  61. '''
  62. for ev, ev_args, ev_kwargs in emitter.fired_events:
  63. if ev != event:
  64. continue
  65. if any(i not in ev_args for i in args):
  66. continue
  67. if any(i not in ev_kwargs for i in kwargs):
  68. continue
  69. return
  70. self.fail('event {!r} did not fire on {!r}'.format(event, emitter))
  71. def assertEventNotFired(self, emitter, event, args=[], kwargs=[]):
  72. '''Check whether event was fired on given emitter. Fail if it did.
  73. :param emitter: emitter which is being checked
  74. :type emitter: :py:class:`TestEmitter`
  75. :param str event: event identifier
  76. :param list args: when given, all items must appear in args passed to event
  77. :param list kwargs: when given, all items must appear in kwargs passed to event
  78. '''
  79. for ev, ev_args, ev_kwargs in emitter.fired_events:
  80. if ev != event:
  81. continue
  82. if any(i not in ev_args for i in args):
  83. continue
  84. if any(i not in ev_kwargs for i in kwargs):
  85. continue
  86. self.fail('event {!r} did fire on {!r}'.format(event, emitter))
  87. return