Skip to content

Commit

Permalink
Import tmt SubResults into ReportPortal
Browse files Browse the repository at this point in the history
  • Loading branch information
seberm committed Oct 30, 2024
1 parent 2ce3538 commit 11d5bc3
Showing 1 changed file with 53 additions and 10 deletions.
63 changes: 53 additions & 10 deletions tmt/steps/report/reportportal.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import dataclasses
import datetime
import os
import re
from time import time
from typing import TYPE_CHECKING, Any, Optional, overload

import requests
Expand Down Expand Up @@ -187,7 +187,7 @@ class ReportReportPortalData(tmt.steps.report.ReportStepData):
@tmt.steps.provides_method("reportportal")
class ReportReportPortal(tmt.steps.report.ReportPlugin[ReportReportPortalData]):
"""
Report test results to a ReportPortal instance via API.
Report test results and their subresults to a ReportPortal instance via API.
For communication with Report Portal API is necessary to provide
following options:
Expand Down Expand Up @@ -281,8 +281,8 @@ def check_options(self) -> None:
"may cause an unexpected behaviour with launch-per-plan structure")

@property
def time(self) -> str:
return str(int(time() * 1000))
def datetime(self) -> str:
return datetime.datetime.now(datetime.timezone.utc).isoformat()

@property
def headers(self) -> dict[str, str]:
Expand Down Expand Up @@ -396,13 +396,14 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None:
self.warn("SSL verification is disabled for all requests being made to ReportPortal "
f"instance ({self.data.url}).")

launch_time = self.time
launch_time = self.datetime

# Support for idle tests
executed = bool(self.step.plan.execute.results())
if executed:
# launch time should be the earliest start time of all plans
launch_time = min([r.start_time or self.time
# TODO: Does the 'min' work with datetime isoformat correctly?
launch_time = min([r.start_time or self.datetime
for r in self.step.plan.execute.results()])

# Create launch, suites (if "--suite_per_plan") and tests;
Expand Down Expand Up @@ -533,7 +534,7 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None:

for result, test in self.step.plan.execute.results_for_tests(
self.step.plan.discover.tests()):
test_time = self.time
test_time = self.datetime
test_name = None
test_description = ''
test_link = None
Expand All @@ -544,7 +545,7 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None:
if result:
serial_number = result.serial_number
test_name = result.name
test_time = result.start_time or self.time
test_time = result.start_time or self.datetime
# for guests, save their primary address
if result.guest.primary_address:
item_attributes.append({
Expand Down Expand Up @@ -595,16 +596,19 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None:
"type": "step",
"testCaseId": test_id,
"startTime": test_time})

item_uuid = yaml_to_dict(response.text).get("id")
assert item_uuid is not None
self.verbose("uuid", item_uuid, "yellow", shift=1)
self.data.test_uuids[serial_number] = item_uuid
else:
item_uuid = self.data.test_uuids[serial_number]

# Support for idle tests
status = "SKIPPED"
if result:
# For each log
# TODO: Try to save logs for subresults?
for index, log_path in enumerate(result.log):
try:
log = self.step.plan.execute.read(log_path)
Expand Down Expand Up @@ -636,9 +640,47 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None:
"level": "ERROR",
"time": result.end_time})

test_time = result.end_time or self.time
test_time = result.end_time or self.datetime

# Finish the test item
# Also create (and *finish*) the child test item for every tmt subresult and
# map it under parent test item
for subresult in result.subresult:
# Create a child item
response = self.rp_api_post(
session=session,
path=f"item/{item_uuid}",
json={
"name": subresult.name,
# TODO: Decide which attributes we want to set for subresults
# "description": test_description,
# "attributes": item_attributes,
# "parameters": env_vars,
# "codeRef": test_link,
"launchUuid": launch_uuid,
"type": "step",
# "testCaseId": test_id,
"startTime": subresult.start_time or self.datetime})

child_item_uuid = yaml_to_dict(response.text).get("id")
assert child_item_uuid is not None

# Finish the child item
response = self.rp_api_put(
session=session,
path=f"item/{item_uuid}",
json={
"launchUuid": launch_uuid,
"status": self.TMT_TO_RP_RESULT_STATUS[subresult.result],
# TODO: Workaround: The problem is, that the `start-time` for
# subresults is not set by `tmt-report-result` and the `end-time`
# **is** and it's **lower** than autogenerated `start-time` set by
# `self.datetime`.
# "endTime": subresult.end_time,
"endTime": self.datetime})

self.verbose("child uuid", child_item_uuid, "yellow", shift=2)

# Finish the parent test item
response = self.rp_api_put(
session=session,
path=f"item/{item_uuid}",
Expand All @@ -648,6 +690,7 @@ def go(self, *, logger: Optional[tmt.log.Logger] = None) -> None:
"status": status,
"issue": {
"issueType": self.get_defect_type_locator(session, defect_type)}})

launch_time = test_time

if create_suite:
Expand Down

0 comments on commit 11d5bc3

Please sign in to comment.