Skip to content

Commit d46bfe4

Browse files
committed
--flatten-keywords feature initial implementation
1 parent 6c94753 commit d46bfe4

File tree

2 files changed

+137
-9
lines changed

2 files changed

+137
-9
lines changed

robotframework_reportportal/listener.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class __DummyContext:
6767
DEFAULT_BINARY_FILE_TYPE = "application/octet-stream"
6868
TRUNCATION_SIGN = "...'"
6969
REMOVED_KEYWORD_CONTENT_LOG = "Content removed using the --remove-keywords option."
70+
FLATTENED_KEYWORD_CONTENT_LOG = "Content flattened."
7071
REMOVED_WUKS_KEYWORD_LOG = "{number} failing items removed using the --remove-keywords option."
7172
REMOVED_FOR_WHILE_KEYWORD_LOG = "{number} passing items removed using the --remove-keywords option."
7273
WUKS_KEYWORD_NAME = "BuiltIn.Wait Until Keyword Succeeds"
@@ -441,6 +442,13 @@ def start_test(self, name: str, attributes: Dict, ts: Optional[Any] = None) -> N
441442
test.rp_item_id = self.service.start_test(test=test, ts=ts)
442443
self._add_current_item(test)
443444

445+
def _log_data_removed(self, item_id: str, timestamp: str, message: str) -> None:
446+
msg = LogMessage(message)
447+
msg.level = "DEBUG"
448+
msg.item_id = item_id
449+
msg.timestamp = timestamp
450+
self.__post_log_message(msg)
451+
444452
def _log_keyword_content_removed(self, item_id: str, timestamp: str) -> None:
445453
self._log_data_removed(item_id, timestamp, REMOVED_KEYWORD_CONTENT_LOG)
446454

@@ -464,13 +472,6 @@ def end_test(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = None)
464472
self._remove_current_item()
465473
self.service.finish_test(test=test, ts=ts)
466474

467-
def _log_data_removed(self, item_id: str, timestamp: str, message: str) -> None:
468-
msg = LogMessage(message)
469-
msg.level = "DEBUG"
470-
msg.item_id = item_id
471-
msg.timestamp = timestamp
472-
self.__post_log_message(msg)
473-
474475
def _do_start_keyword(self, keyword: Keyword, ts: Optional[str] = None) -> None:
475476
logger.debug(f"ReportPortal - Start Keyword: {keyword.robot_attributes}")
476477
keyword.rp_item_id = self.service.start_keyword(keyword=keyword, ts=ts)
@@ -483,8 +484,13 @@ def _should_remove(self, keyword: Keyword) -> Optional[KeywordMatch]:
483484
return None
484485

485486
def _should_flatten(self, keyword: Keyword) -> bool:
487+
if not isinstance(keyword, Keyword):
488+
return False
486489
return any(matcher.match(keyword) for matcher in self._flatten_keyword_filters)
487490

491+
def _log_keyword_content_flattened(self, item_id: str, timestamp: str) -> None:
492+
self._log_data_removed(item_id, timestamp, FLATTENED_KEYWORD_CONTENT_LOG)
493+
488494
@check_rp_enabled
489495
def start_keyword(self, name: str, attributes: Dict, ts: Optional[Any] = None) -> None:
490496
"""Start a new keyword(test step) at the ReportPortal.
@@ -514,7 +520,13 @@ def start_keyword(self, name: str, attributes: Dict, ts: Optional[Any] = None) -
514520
parent.skipped_keywords.append(kwd)
515521
kwd.posted = False
516522
else:
517-
self._do_start_keyword(kwd, ts)
523+
if parent.flattened or self._should_flatten(parent):
524+
kwd.rp_item_id = parent.rp_item_id
525+
kwd.flattened = True
526+
else:
527+
self._do_start_keyword(kwd, ts)
528+
if not kwd.flattened and self._should_flatten(kwd):
529+
self._log_keyword_content_flattened(kwd.rp_item_id, kwd.start_time)
518530
if skip_data:
519531
kwd.remove_origin = kwd
520532
if self._remove_data_passed_tests:
@@ -575,7 +587,7 @@ def end_keyword(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = No
575587
self._log_keyword_content_removed(kwd.rp_item_id, kwd.start_time)
576588

577589
self._remove_current_item()
578-
if not kwd.posted:
590+
if not kwd.posted or kwd.flattened:
579591
return
580592
self._do_end_keyword(kwd, ts)
581593

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Copyright 2025 EPAM Systems
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
from unittest import mock
17+
from tests import REPORT_PORTAL_SERVICE
18+
from tests.helpers import utils
19+
from tests.helpers.utils import DEFAULT_VARIABLES
20+
21+
22+
@pytest.mark.parametrize(
23+
"file, keyword_to_flatten, exit_code, expected_statuses, log_number, skip_idx, skip_message",
24+
[
25+
(
26+
"examples/rkie_keyword_error.robot",
27+
"name: BuiltIn.Run Keyword And Ignore Error",
28+
0,
29+
["PASSED"] * 3 + ["SKIPPED"] * 3 + ["PASSED"] * 3,
30+
7,
31+
0,
32+
"Content flattened.",
33+
),
34+
# (
35+
# "examples/for_keyword.robot",
36+
# "FOR",
37+
# 0,
38+
# ["PASSED"] * 5,
39+
# 2,
40+
# 0,
41+
# "2 passing items flattened using the --flatten-keywords option.",
42+
# ),
43+
# (
44+
# "examples/while_keyword.robot",
45+
# "WHILE",
46+
# 0,
47+
# ["PASSED"] * 7,
48+
# 5,
49+
# 2,
50+
# "2 passing items flattened using the --flatten-keywords option.",
51+
# ),
52+
# (
53+
# "examples/for_keyword_failed.robot",
54+
# "FOR",
55+
# 1,
56+
# ["PASSED"] + ["FAILED"] * 6,
57+
# 3,
58+
# 0,
59+
# "1 passing items flattened using the --flatten-keywords option.",
60+
# ),
61+
# (
62+
# "examples/while_keyword_failed.robot",
63+
# "WHILE",
64+
# 1,
65+
# ["PASSED"] * 3 + ["FAILED"] * 6,
66+
# 6,
67+
# 2,
68+
# "1 passing items flattened using the --flatten-keywords option.",
69+
# ),
70+
# (
71+
# "examples/wuks_keyword.robot",
72+
# "WUKS",
73+
# 0,
74+
# ["PASSED"] * 2 + ["FAILED"] * 3 + ["PASSED"] * 2 + ["SKIPPED"] * 2 + ["PASSED"] * 4,
75+
# 6,
76+
# 0,
77+
# "1 failing items flattened using the --flatten-keywords option.",
78+
# ),
79+
# (
80+
# "examples/wuks_keyword_failed.robot",
81+
# "WUKS",
82+
# 1,
83+
# ["PASSED"] * 2 + ["FAILED"] * 6,
84+
# 4,
85+
# 0,
86+
# "2 failing items flattened using the --flatten-keywords option.",
87+
# ),
88+
],
89+
)
90+
@mock.patch(REPORT_PORTAL_SERVICE)
91+
def test_keyword_flatten(
92+
mock_client_init, file, keyword_to_flatten, exit_code, expected_statuses, log_number, skip_idx, skip_message
93+
):
94+
mock_client = mock_client_init.return_value
95+
mock_client.start_test_item.side_effect = utils.item_id_gen
96+
97+
variables = DEFAULT_VARIABLES.copy()
98+
variables["RP_FLATTEN_KEYWORDS"] = True
99+
result = utils.run_robot_tests([file], variables=variables, arguments={"--flatten-keywords": keyword_to_flatten})
100+
assert result == exit_code
101+
102+
launch_start = mock_client.start_launch.call_args_list
103+
launch_finish = mock_client.finish_launch.call_args_list
104+
assert len(launch_start) == len(launch_finish) == 1
105+
106+
item_start_calls = mock_client.start_test_item.call_args_list
107+
item_finish_calls = mock_client.finish_test_item.call_args_list
108+
assert len(item_start_calls) == len(item_finish_calls)
109+
assert len(item_finish_calls) == len(expected_statuses)
110+
111+
statuses = [finish[1]["status"] for finish in item_finish_calls]
112+
assert statuses == expected_statuses
113+
114+
log_calls = utils.get_log_calls(mock_client)
115+
assert len(log_calls) == log_number
116+
assert sorted(log_calls, key=lambda x: x[1]["time"])[skip_idx][1]["message"] == skip_message

0 commit comments

Comments
 (0)