You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ansible/test/units/errors/test_utils.py

202 lines
5.1 KiB
Python

from __future__ import annotations
import pytest
from ansible._internal._errors import _error_factory
from ansible.errors import AnsibleError
from ansible._internal._datatag._tags import Origin
from ansible._internal._errors._utils import format_exception_message
from ansible.utils.display import _format_message
from ansible.module_utils._internal import _messages
def raise_exceptions(exceptions: list[BaseException]) -> None:
if len(exceptions) > 1:
try:
raise_exceptions(exceptions[1:])
except Exception as ex:
raise exceptions[0] from ex
raise exceptions[0]
_shared_cause = Exception('shared cause')
_origin_x = Origin(path='/x')
_origin_y = Origin(path='/y')
@pytest.mark.parametrize("exceptions, expected_message_chain, expected_formatted_message", (
([AnsibleError('a')], 'a', None),
([AnsibleError('a'), AnsibleError('b')], 'a: b', None),
([AnsibleError('a: b'), AnsibleError('b')], 'a: b', None),
([Exception('a')], 'a', None),
([Exception('a'), Exception('b')], 'a: b', None),
([Exception('a: b'), Exception('b')], 'a: b', None),
([AnsibleError('a'), Exception('b')], 'a: b', None),
([AnsibleError('a: b'), Exception('b')], 'a: b', None),
([Exception('a'), AnsibleError('b')], 'a: b', None),
([Exception('a: b'), AnsibleError('b')], 'a: b', None),
([AnsibleError('a'), AnsibleError('b'), Exception('c'), Exception('d')], 'a: b: c: d', None),
([AnsibleError('a: b: c: d'), AnsibleError('b'), Exception('c: d'), Exception('d')], 'a: b: c: d', None),
# collapsing help_text
(
[
AnsibleError('a', help_text='one'),
Exception('b'),
],
'a: b',
(
'a: b one'
),
),
(
[
AnsibleError('a', help_text='one'),
AnsibleError('b', help_text='one'),
],
'a: b',
(
'a: b one'
),
),
(
[
AnsibleError('a', help_text='one'),
Exception('b'),
AnsibleError('c', help_text='one'),
],
'a: b: c',
(
'a: b: c one'
),
),
(
[
AnsibleError('a', help_text='one'),
AnsibleError('b', help_text='two'),
],
'a: b',
(
'a: b\n\n'
'a one\n\n'
'<<< caused by >>>\n\n'
'b two'
),
),
(
[
AnsibleError('a'),
AnsibleError('b', help_text='one'),
],
'a: b',
(
'a: b\n\n'
'a\n\n'
'<<< caused by >>>\n\n'
'b one'
),
),
# collapsing origin
(
[
AnsibleError('a', obj=_origin_x.tag('x'), orig_exc=Exception('ignored')),
Exception('b'),
],
'a: b',
(
'a: b\n'
'Origin: /x'
),
),
(
[
AnsibleError('a', obj=_origin_x.tag('x'), orig_exc=_shared_cause),
_shared_cause,
],
'a: shared cause',
(
'a: shared cause\n'
'Origin: /x'
),
),
(
[
# same as above, but exercises the old `orig_exc` path that displays a warning
AnsibleError('a', obj=_origin_x.tag('x'), orig_exc=Exception('b')),
],
'a: b',
(
'a: b\n'
'Origin: /x'
),
),
(
[
AnsibleError('a', obj=_origin_x.tag('x')),
AnsibleError('b', obj=_origin_x.tag('x')),
],
'a: b',
(
'a: b\n'
'Origin: /x'
),
),
(
[
AnsibleError('a', obj=_origin_x.tag('x')),
Exception('b'),
AnsibleError('c', obj=_origin_x.tag('x')),
],
'a: b: c',
(
'a: b: c\n'
'Origin: /x'
),
),
(
[
AnsibleError('a', obj=_origin_x.tag('x')),
AnsibleError('b', obj=_origin_y.tag('x')),
],
'a: b',
(
'a: b\n\n'
'a\n'
'Origin: /x\n\n'
'<<< caused by >>>\n\n'
'b\n'
'Origin: /y'
),
),
(
[
AnsibleError('a'),
AnsibleError('b', obj=_origin_y.tag('x')),
],
'a: b',
(
'a: b\n\n'
'a\n\n'
'<<< caused by >>>\n\n'
'b\n'
'Origin: /y'
),
),
), ids=str)
def test_error_messages(exceptions: list[BaseException], expected_message_chain: str, expected_formatted_message: str | None) -> None:
with pytest.raises(Exception) as error:
raise_exceptions(exceptions)
event = _error_factory.ControllerEventFactory.from_exception(error.value, False)
message_chain = format_exception_message(error.value)
formatted_message = _format_message(_messages.ErrorSummary(event=event), False)
assert message_chain == expected_message_chain
assert formatted_message.strip() == (expected_formatted_message or expected_message_chain)