from collections import OrderedDict
from contextlib import contextmanager
from allure_commons._core import plugin_manager
from allure_commons.model2 import TestResultContainer
from allure_commons.model2 import TestResult
from allure_commons.model2 import Attachment, ATTACHMENT_PATTERN
from allure_commons.model2 import TestStepResult
from allure_commons.model2 import ExecutableItem
from allure_commons.model2 import TestBeforeResult
from allure_commons.model2 import TestAfterResult
from allure_commons.utils import uuid4
from allure_commons.utils import now
from allure_commons.types import AttachmentType
class AllureLifecycle:
def __init__(self):
self._items = OrderedDict()
def _get_item(self, uuid=None, item_type=None):
uuid = uuid or self._last_item_uuid(item_type=item_type)
return self._items.get(uuid)
def _pop_item(self, uuid=None, item_type=None):
uuid = uuid or self._last_item_uuid(item_type=item_type)
return self._items.pop(uuid, None)
def _last_item_uuid(self, item_type=None):
for uuid in reversed(self._items):
item = self._items.get(uuid)
if item_type is None:
return uuid
elif isinstance(item, item_type):
return uuid
@contextmanager
def schedule_test_case(self, uuid=None):
test_result = TestResult()
test_result.uuid = uuid or uuid4()
self._items[test_result.uuid] = test_result
yield test_result
@contextmanager
def update_test_case(self, uuid=None):
yield self._get_item(uuid=uuid, item_type=TestResult)
def write_test_case(self, uuid=None):
test_result = self._pop_item(uuid=uuid, item_type=TestResult)
if test_result:
plugin_manager.hook.report_result(result=test_result)
@contextmanager
def start_step(self, parent_uuid=None, uuid=None):
parent = self._get_item(uuid=parent_uuid, item_type=ExecutableItem)
step = TestStepResult()
step.start = now()
parent.steps.append(step)
self._items[uuid or uuid4()] = step
yield step
@contextmanager
def update_step(self, uuid=None):
yield self._get_item(uuid=uuid, item_type=TestStepResult)
def stop_step(self, uuid=None):
step = self._pop_item(uuid=uuid, item_type=TestStepResult)
if step and not step.stop:
step.stop = now()
@contextmanager
def start_container(self, uuid=None):
container = TestResultContainer(uuid=uuid or uuid4())
self._items[container.uuid] = container
yield container
def containers(self):
for item in self._items.values():
if isinstance(item, TestResultContainer):
yield item
@contextmanager
def update_container(self, uuid=None):
yield self._get_item(uuid=uuid, item_type=TestResultContainer)
def write_container(self, uuid=None):
container = self._pop_item(uuid=uuid, item_type=TestResultContainer)
if container and (container.befores or container.afters):
plugin_manager.hook.report_container(container=container)
@contextmanager
def start_before_fixture(self, parent_uuid=None, uuid=None):
fixture = TestBeforeResult()
parent = self._get_item(uuid=parent_uuid, item_type=TestResultContainer)
if parent:
parent.befores.append(fixture)
self._items[uuid or uuid4()] = fixture
yield fixture
@contextmanager
def update_before_fixture(self, uuid=None):
yield self._get_item(uuid=uuid, item_type=TestBeforeResult)
def stop_before_fixture(self, uuid=None):
fixture = self._pop_item(uuid=uuid, item_type=TestBeforeResult)
if fixture and not fixture.stop:
fixture.stop = now()
@contextmanager
def start_after_fixture(self, parent_uuid=None, uuid=None):
fixture = TestAfterResult()
parent = self._get_item(uuid=parent_uuid, item_type=TestResultContainer)
if parent:
parent.afters.append(fixture)
self._items[uuid or uuid4()] = fixture
yield fixture
@contextmanager
def update_after_fixture(self, uuid=None):
yield self._get_item(uuid=uuid, item_type=TestAfterResult)
def stop_after_fixture(self, uuid=None):
fixture = self._pop_item(uuid=uuid, item_type=TestAfterResult)
if fixture and not fixture.stop:
fixture.stop = now()
def _attach(self, uuid, name=None, attachment_type=None, extension=None, parent_uuid=None):
mime_type = attachment_type
extension = extension if extension else 'attach'
if type(attachment_type) is AttachmentType:
extension = attachment_type.extension
mime_type = attachment_type.mime_type
file_name = ATTACHMENT_PATTERN.format(prefix=uuid, ext=extension)
attachment = Attachment(source=file_name, name=name, type=mime_type)
last_uuid = parent_uuid if parent_uuid else self._last_item_uuid(ExecutableItem)
self._items[last_uuid].attachments.append(attachment)
return file_name
def attach_file(self, uuid, source, name=None, attachment_type=None, extension=None, parent_uuid=None):
file_name = self._attach(uuid, name=name, attachment_type=attachment_type,
extension=extension, parent_uuid=parent_uuid)
plugin_manager.hook.report_attached_file(source=source, file_name=file_name)
def attach_data(self, uuid, body, name=None, attachment_type=None, extension=None, parent_uuid=None):
file_name = self._attach(uuid, name=name, attachment_type=attachment_type,
extension=extension, parent_uuid=parent_uuid)
plugin_manager.hook.report_attached_data(body=body, file_name=file_name)