diff --git a/tmt/steps/report/reportportal.py b/tmt/steps/report/reportportal.py index 6b08daf364..489e176ad9 100644 --- a/tmt/steps/report/reportportal.py +++ b/tmt/steps/report/reportportal.py @@ -36,6 +36,13 @@ def _str_env_to_default(option: str, default: Optional[str]) -> Optional[str]: return str(os.getenv(env_var)) +def _filter_invalid_chars(data: str) -> str: + return re.sub( + '[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', + '', + data) + + @dataclasses.dataclass class ReportReportPortalData(tmt.steps.report.ReportStepData): @@ -226,13 +233,14 @@ class ReportReportPortal(tmt.steps.report.ReportPlugin[ReportReportPortalData]): def handle_response(self, response: requests.Response) -> None: """ Check the endpoint response and raise an exception if needed """ - if not response.ok: - raise tmt.utils.ReportError( - f"Received non-ok status code from ReportPortal: {response.text}") - self.debug("Response code from the endpoint", response.status_code) self.debug("Message from the endpoint", response.text) + if not response.ok: + raise tmt.utils.ReportError( + f"Received non-ok status code {response.status_code} " + f"from ReportPortal: {response.text}") + def check_options(self) -> None: """ Check options for known troublesome combinations """ # TODO: Update restriction of forbidden option combinations based on feedback. @@ -393,7 +401,13 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None: suite_description += f"
{self.data.artifacts_url}" # Communication with RP instance - with tmt.utils.retry_session() as session: + with tmt.utils.retry_session(status_forcelist=( + 429, # Too Many Requests + 500, # Internal Server Error + 502, # Bad Gateway + 503, # Service Unavailable + 504, # Gateway Timeout + )) as session: if create_launch: @@ -528,7 +542,7 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None: response = session.post( url=f"{self.get_url()}/log/entry", headers=self.get_headers(), - json={"message": log, + json={"message": _filter_invalid_chars(log), "itemUuid": item_uuid, "launchUuid": launch_uuid, "level": level, @@ -537,7 +551,7 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None: # Write out failures if index == 0 and status == "FAILED": - message = result.failures(log) + message = _filter_invalid_chars(result.failures(log)) response = session.post( url=f"{self.get_url()}/log/entry", headers=self.get_headers(),