diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..97d5f5f --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.jpg binary diff --git a/CHANGELOG.md b/CHANGELOG.md index d10111f..542d248 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog ## [Unreleased] +### Fixed +- SETUP / TEARDOWN keyword removing, by @HardNorth + +## [5.6.1] ### Added - `RP_FLATTEN_KEYWORDS` configuration variable, by @HardNorth - `--flatten-keywords` argument support, by @HardNorth diff --git a/examples/before_after/before_suite_with_steps_fail.robot b/examples/before_after/before_suite_with_steps_fail.robot new file mode 100644 index 0000000..e6ed5af --- /dev/null +++ b/examples/before_after/before_suite_with_steps_fail.robot @@ -0,0 +1,10 @@ +*** Settings *** +Suite Setup Log suite setup + +*** Test Cases *** +My first test + Log My first test + +*** Keywords *** +Log suite setup + Fail Suite setup step diff --git a/robotframework_reportportal/listener.py b/robotframework_reportportal/listener.py index b3d5680..7de23db 100644 --- a/robotframework_reportportal/listener.py +++ b/robotframework_reportportal/listener.py @@ -355,8 +355,7 @@ def _process_keyword_flatten(self): elif pattern_str_upper == "WHILE": self._flatten_keyword_filters.append(WHILE_KEYWORD_MATCH) else: - self._flatten_keyword_filters.append(FOR_KEYWORD_MATCH) - self._flatten_keyword_filters.append(WHILE_KEYWORD_MATCH) + self._flatten_keyword_filters.extend([FOR_KEYWORD_MATCH, WHILE_KEYWORD_MATCH]) continue process_keyword_names_and_tags(self._flatten_keyword_filters, pattern_str) @@ -411,6 +410,16 @@ def start_suite(self, name: str, attributes: Dict, ts: Optional[Any] = None) -> suite.rp_item_id = self.service.start_suite(suite=suite, ts=ts) self._add_current_item(suite) + def _log_data_removed(self, item_id: str, timestamp: str, message: str) -> None: + msg = LogMessage(message) + msg.level = "DEBUG" + msg.item_id = item_id + msg.timestamp = timestamp + self.__post_log_message(msg) + + def _log_keyword_content_removed(self, item_id: str, timestamp: str) -> None: + self._log_data_removed(item_id, timestamp, REMOVED_KEYWORD_CONTENT_LOG) + @check_rp_enabled def end_suite(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = None) -> None: """Finish started test suite at the ReportPortal. @@ -421,6 +430,11 @@ def end_suite(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = None """ suite = self._remove_current_item().update(attributes) logger.debug(f"ReportPortal - End Suite: {suite.robot_attributes}") + if attributes["status"] == "FAIL" and self._remove_data_passed_tests: + self._post_skipped_keywords(suite) + elif self._remove_data_passed_tests: + for kwd in suite.skipped_keywords: + self._log_keyword_content_removed(kwd.rp_item_id, kwd.start_time) self.service.finish_suite(suite=suite, ts=ts) if attributes["id"] == MAIN_SUITE_ID: self.finish_launch(attributes, ts) @@ -442,16 +456,6 @@ def start_test(self, name: str, attributes: Dict, ts: Optional[Any] = None) -> N test.rp_item_id = self.service.start_test(test=test, ts=ts) self._add_current_item(test) - def _log_data_removed(self, item_id: str, timestamp: str, message: str) -> None: - msg = LogMessage(message) - msg.level = "DEBUG" - msg.item_id = item_id - msg.timestamp = timestamp - self.__post_log_message(msg) - - def _log_keyword_content_removed(self, item_id: str, timestamp: str) -> None: - self._log_data_removed(item_id, timestamp, REMOVED_KEYWORD_CONTENT_LOG) - @check_rp_enabled def end_test(self, _: Optional[str], attributes: Dict, ts: Optional[Any] = None) -> None: """Finish started test case at the ReportPortal. diff --git a/robotframework_reportportal/model.py b/robotframework_reportportal/model.py index cfd60ae..d9747c9 100644 --- a/robotframework_reportportal/model.py +++ b/robotframework_reportportal/model.py @@ -36,6 +36,8 @@ class Entity: remove_origin: Optional[Any] rp_item_id: Optional[str] parent: Optional["Entity"] + skipped_keywords: List["Keyword"] + posted: bool def __init__(self, entity_type: str, parent: Optional["Entity"]): """Initialize required attributes. @@ -50,6 +52,8 @@ def __init__(self, entity_type: str, parent: Optional["Entity"]): self.flattened = False self.remove_filter = None self.remove_origin = None + self.skipped_keywords = [] + self.posted = True @property def rp_parent_item_id(self): @@ -94,8 +98,6 @@ class Keyword(Entity): tags: List[str] type: str = "KEYWORD" skipped_logs: List[LogMessage] - skipped_keywords: List["Keyword"] - posted: bool def __init__(self, name: str, robot_attributes: Dict[str, Any], parent: Entity): """Initialize required attributes. @@ -118,9 +120,7 @@ def __init__(self, name: str, robot_attributes: Dict[str, Any], parent: Entity): self.status = robot_attributes.get("status") self.tags = robot_attributes["tags"] self.type = "KEYWORD" - self.skipped_keywords = [] self.skipped_logs = [] - self.posted = True def get_name(self) -> str: """Get name of the keyword suitable for ReportPortal.""" @@ -257,7 +257,6 @@ class Test(Entity): start_time: str status: str template: str - skipped_keywords: List[Keyword] def __init__(self, name: str, robot_attributes: Dict[str, Any], test_attributes: List[str], parent: Entity): """Initialize required attributes. @@ -281,7 +280,6 @@ def __init__(self, name: str, robot_attributes: Dict[str, Any], test_attributes: self.start_time = robot_attributes["starttime"] self.status = robot_attributes.get("status") self.template = robot_attributes["template"] - self.skipped_keywords = [] @property def critical(self) -> bool: diff --git a/setup.py b/setup.py index cd16f2c..89085fa 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ from setuptools import setup -__version__ = "5.6.1" +__version__ = "5.6.2" def read_file(fname): diff --git a/tests/integration/test_logger.py b/tests/integration/test_logger.py index 4b4b379..ec8adb6 100644 --- a/tests/integration/test_logger.py +++ b/tests/integration/test_logger.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import platform from unittest import mock from tests import REPORT_PORTAL_SERVICE @@ -33,6 +34,11 @@ def test_launch_log(mock_client_init): @mock.patch(REPORT_PORTAL_SERVICE) def test_binary_file_log(mock_client_init): + if platform.system() == "Linux" and platform.release() == "6.8.0-1017-azure": + # GitHub Actions Linux runner has an issue with binary data reading + data_type = "application/octet-stream" + else: + data_type = "image/jpeg" result = utils.run_robot_tests(["examples/binary_file_log_as_text.robot"]) assert result == 0 # the test successfully passed @@ -41,5 +47,5 @@ def test_binary_file_log(mock_client_init): assert len(calls) == 3 messages = set(map(lambda x: x[1]["message"], calls)) - error_msg = 'Binary data of type "image/jpeg" logging skipped, as it was processed as text and hence corrupted.' + error_msg = f'Binary data of type "{data_type}" logging skipped, as it was processed as text and hence corrupted.' assert error_msg in messages diff --git a/tests/integration/test_remove_keywords.py b/tests/integration/test_remove_keywords.py index 6191da2..0ea288a 100644 --- a/tests/integration/test_remove_keywords.py +++ b/tests/integration/test_remove_keywords.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import platform from unittest import mock import pytest @@ -44,6 +45,11 @@ def test_remove_keyword_not_provided(mock_client_init): assert statuses == ["PASSED"] * 9 +def is_gha_agent() -> bool: + # GitHub Actions Linux runner has an issue with binary data reading + return platform.system() == "Linux" and platform.release() == "6.8.0-1017-azure" + + @pytest.mark.parametrize( "file, keyword_to_remove, exit_code, expected_statuses, log_number, skip_idx, skip_message", [ @@ -273,7 +279,8 @@ def test_remove_keyword_not_provided(mock_client_init): ["PASSED"] * 5, 3, 2, - 'Binary data of type "image/jpeg" logging skipped, as it was processed as text and hence corrupted.', + f'Binary data of type "{"application/octet-stream" if is_gha_agent else "image/jpeg"}" logging skipped, as' + " it was processed as text and hence corrupted.", ), ( "examples/rkie_keyword.robot", @@ -302,6 +309,33 @@ def test_remove_keyword_not_provided(mock_client_init): 2, "To less executions error", ), + ( + "examples/before_after/before_suite_with_steps.robot", + "PASSED", + 0, + ["PASSED"] * 4, + 2, + 0, + "Content removed using the --remove-keywords option.", + ), + ( + "examples/before_after/after_suite_with_steps.robot", + "PASSED", + 0, + ["PASSED"] * 4, + 2, + 1, + "Content removed using the --remove-keywords option.", + ), + ( + "examples/before_after/before_suite_with_steps_fail.robot", + "PASSED", + 1, + ["FAILED"] * 4, + 1, + 0, + "Suite setup step", + ), ], ) @mock.patch(REPORT_PORTAL_SERVICE)