_allure.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. from functools import wraps
  2. from typing import Any, Callable, TypeVar
  3. from allure_commons._core import plugin_manager
  4. from allure_commons.types import LabelType, LinkType, ParameterMode
  5. from allure_commons.utils import uuid4
  6. from allure_commons.utils import func_parameters, represent
  7. _TFunc = TypeVar("_TFunc", bound=Callable[..., Any])
  8. def safely(result):
  9. if result:
  10. return result[0]
  11. else:
  12. def dummy(function):
  13. return function
  14. return dummy
  15. def title(test_title):
  16. return safely(plugin_manager.hook.decorate_as_title(test_title=test_title))
  17. def description(test_description):
  18. return safely(plugin_manager.hook.decorate_as_description(test_description=test_description))
  19. def description_html(test_description_html):
  20. return safely(plugin_manager.hook.decorate_as_description_html(test_description_html=test_description_html))
  21. def label(label_type, *labels):
  22. return safely(plugin_manager.hook.decorate_as_label(label_type=label_type, labels=labels))
  23. def severity(severity_level):
  24. return label(LabelType.SEVERITY, severity_level)
  25. def epic(*epics):
  26. return label(LabelType.EPIC, *epics)
  27. def feature(*features):
  28. return label(LabelType.FEATURE, *features)
  29. def story(*stories):
  30. return label(LabelType.STORY, *stories)
  31. def suite(suite_name):
  32. return label(LabelType.SUITE, suite_name)
  33. def parent_suite(parent_suite_name):
  34. return label(LabelType.PARENT_SUITE, parent_suite_name)
  35. def sub_suite(sub_suite_name):
  36. return label(LabelType.SUB_SUITE, sub_suite_name)
  37. def tag(*tags):
  38. return label(LabelType.TAG, *tags)
  39. def id(id): # noqa: A001,A002
  40. return label(LabelType.ID, id)
  41. def manual(fn):
  42. return label(LabelType.MANUAL, True)(fn)
  43. def link(url, link_type=LinkType.LINK, name=None):
  44. return safely(plugin_manager.hook.decorate_as_link(url=url, link_type=link_type, name=name))
  45. def issue(url, name=None):
  46. return link(url, link_type=LinkType.ISSUE, name=name)
  47. def testcase(url, name=None):
  48. return link(url, link_type=LinkType.TEST_CASE, name=name)
  49. class Dynamic:
  50. @staticmethod
  51. def title(test_title):
  52. plugin_manager.hook.add_title(test_title=test_title)
  53. @staticmethod
  54. def description(test_description):
  55. plugin_manager.hook.add_description(test_description=test_description)
  56. @staticmethod
  57. def description_html(test_description_html):
  58. plugin_manager.hook.add_description_html(test_description_html=test_description_html)
  59. @staticmethod
  60. def label(label_type, *labels):
  61. plugin_manager.hook.add_label(label_type=label_type, labels=labels)
  62. @staticmethod
  63. def severity(severity_level):
  64. Dynamic.label(LabelType.SEVERITY, severity_level)
  65. @staticmethod
  66. def epic(*epics):
  67. Dynamic.label(LabelType.EPIC, *epics)
  68. @staticmethod
  69. def feature(*features):
  70. Dynamic.label(LabelType.FEATURE, *features)
  71. @staticmethod
  72. def story(*stories):
  73. Dynamic.label(LabelType.STORY, *stories)
  74. @staticmethod
  75. def tag(*tags):
  76. Dynamic.label(LabelType.TAG, *tags)
  77. @staticmethod
  78. def id(id): # noqa: A003,A002
  79. Dynamic.label(LabelType.ID, id)
  80. @staticmethod
  81. def link(url, link_type=LinkType.LINK, name=None):
  82. plugin_manager.hook.add_link(url=url, link_type=link_type, name=name)
  83. @staticmethod
  84. def parameter(name, value, excluded=None, mode: ParameterMode = None):
  85. plugin_manager.hook.add_parameter(name=name, value=value, excluded=excluded, mode=mode)
  86. @staticmethod
  87. def issue(url, name=None):
  88. Dynamic.link(url, link_type=LinkType.ISSUE, name=name)
  89. @staticmethod
  90. def testcase(url, name=None):
  91. Dynamic.link(url, link_type=LinkType.TEST_CASE, name=name)
  92. @staticmethod
  93. def suite(suite_name):
  94. Dynamic.label(LabelType.SUITE, suite_name)
  95. @staticmethod
  96. def parent_suite(parent_suite_name):
  97. Dynamic.label(LabelType.PARENT_SUITE, parent_suite_name)
  98. @staticmethod
  99. def sub_suite(sub_suite_name):
  100. Dynamic.label(LabelType.SUB_SUITE, sub_suite_name)
  101. @staticmethod
  102. def manual():
  103. return Dynamic.label(LabelType.MANUAL, True)
  104. def step(title):
  105. if callable(title):
  106. return StepContext(title.__name__, {})(title)
  107. else:
  108. return StepContext(title, {})
  109. class StepContext:
  110. def __init__(self, title, params):
  111. self.title = title
  112. self.params = params
  113. self.uuid = uuid4()
  114. def __enter__(self):
  115. plugin_manager.hook.start_step(uuid=self.uuid, title=self.title, params=self.params)
  116. def __exit__(self, exc_type, exc_val, exc_tb):
  117. plugin_manager.hook.stop_step(uuid=self.uuid, title=self.title, exc_type=exc_type, exc_val=exc_val,
  118. exc_tb=exc_tb)
  119. def __call__(self, func: _TFunc) -> _TFunc:
  120. @wraps(func)
  121. def impl(*a, **kw):
  122. __tracebackhide__ = True
  123. params = func_parameters(func, *a, **kw)
  124. args = list(map(lambda x: represent(x), a))
  125. with StepContext(self.title.format(*args, **params), params):
  126. return func(*a, **kw)
  127. return impl
  128. class Attach:
  129. def __call__(self, body, name=None, attachment_type=None, extension=None):
  130. plugin_manager.hook.attach_data(body=body, name=name, attachment_type=attachment_type, extension=extension)
  131. def file(self, source, name=None, attachment_type=None, extension=None):
  132. plugin_manager.hook.attach_file(source=source, name=name, attachment_type=attachment_type, extension=extension)
  133. attach = Attach()
  134. class fixture:
  135. def __init__(self, fixture_function, parent_uuid=None, name=None):
  136. self._fixture_function = fixture_function
  137. self._parent_uuid = parent_uuid
  138. self._name = name if name else fixture_function.__name__
  139. self._uuid = uuid4()
  140. self.parameters = None
  141. def __call__(self, *args, **kwargs):
  142. self.parameters = func_parameters(self._fixture_function, *args, **kwargs)
  143. with self:
  144. return self._fixture_function(*args, **kwargs)
  145. def __enter__(self):
  146. plugin_manager.hook.start_fixture(parent_uuid=self._parent_uuid,
  147. uuid=self._uuid,
  148. name=self._name,
  149. parameters=self.parameters)
  150. def __exit__(self, exc_type, exc_val, exc_tb):
  151. plugin_manager.hook.stop_fixture(parent_uuid=self._parent_uuid,
  152. uuid=self._uuid,
  153. name=self._name,
  154. exc_type=exc_type,
  155. exc_val=exc_val,
  156. exc_tb=exc_tb)
  157. class test:
  158. def __init__(self, _test, context):
  159. self._test = _test
  160. self._uuid = uuid4()
  161. self.context = context
  162. self.parameters = None
  163. def __call__(self, *args, **kwargs):
  164. self.parameters = func_parameters(self._test, *args, **kwargs)
  165. with self:
  166. return self._test(*args, **kwargs)
  167. def __enter__(self):
  168. plugin_manager.hook.start_test(parent_uuid=None,
  169. uuid=self._uuid,
  170. name=None,
  171. parameters=self.parameters,
  172. context=self.context)
  173. def __exit__(self, exc_type, exc_val, exc_tb):
  174. plugin_manager.hook.stop_test(parent_uuid=None,
  175. uuid=self._uuid,
  176. name=None,
  177. context=self.context,
  178. exc_type=exc_type,
  179. exc_val=exc_val,
  180. exc_tb=exc_tb)