Skip to content

Commit

Permalink
Move timestamp/duration formatting to utils [Step results #5] (teemte…
Browse files Browse the repository at this point in the history
…e#3019)

We will need them from other places, it's not longer just `execute` who
will be dealign with times.

Co-authored-by: Martin Hoyer <[email protected]>
  • Loading branch information
happz and martinhoyer authored Aug 29, 2024
1 parent 002a15a commit db6604b
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 37 deletions.
4 changes: 2 additions & 2 deletions tests/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1176,9 +1176,9 @@ def test_flatten(lists: list[list[Any]], unique: bool, expected: list[Any]) -> N
]
)
def test_format_duration(duration, expected):
from tmt.steps.execute import ExecutePlugin
from tmt.utils import format_duration

assert ExecutePlugin.format_duration(duration) == expected
assert format_duration(duration) == expected


def test_filter_paths(source_dir):
Expand Down
12 changes: 8 additions & 4 deletions tmt/checks/avc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
import tmt.utils
from tmt.checks import Check, CheckPlugin, provides_check
from tmt.result import CheckResult, ResultOutcome
from tmt.utils import CommandOutput, Path, ShellScript, render_run_exception_streams
from tmt.utils import (
CommandOutput,
Path,
ShellScript,
format_timestamp,
render_run_exception_streams,
)

if TYPE_CHECKING:
import tmt.base
Expand Down Expand Up @@ -48,12 +54,10 @@ def _save_report(
:returns: path to the report file.
"""

from tmt.steps.execute import ExecutePlugin

report_filepath = invocation.check_files_path / TEST_POST_AVC_FILENAME

report = [
f'# Reported at {ExecutePlugin.format_timestamp(timestamp)}',
f'# Reported at {format_timestamp(timestamp)}',
*report
]

Expand Down
6 changes: 2 additions & 4 deletions tmt/checks/dmesg.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from tmt.checks import Check, CheckEvent, CheckPlugin, _RawCheck, provides_check
from tmt.result import CheckResult, ResultOutcome
from tmt.steps.provision import GuestCapability
from tmt.utils import Path, field, render_run_exception_streams
from tmt.utils import Path, field, format_timestamp, render_run_exception_streams

if TYPE_CHECKING:
import tmt.base
Expand Down Expand Up @@ -95,11 +95,9 @@ def _save_dmesg(
event: CheckEvent,
logger: tmt.log.Logger) -> tuple[ResultOutcome, Path]:

from tmt.steps.execute import ExecutePlugin

assert invocation.phase.step.workdir is not None # narrow type

timestamp = ExecutePlugin.format_timestamp(datetime.datetime.now(datetime.timezone.utc))
timestamp = format_timestamp(datetime.datetime.now(datetime.timezone.utc))

path = invocation.check_files_path / TEST_POST_DMESG_FILENAME.format(event=event.value)

Expand Down
5 changes: 2 additions & 3 deletions tmt/checks/watchdog.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import tmt.utils
from tmt.checks import Check, CheckPlugin, provides_check
from tmt.result import CheckResult, ResultOutcome
from tmt.utils import Path, field, render_run_exception_streams
from tmt.utils import Path, field, format_timestamp, render_run_exception_streams

if TYPE_CHECKING:
from tmt.steps.execute import TestInvocation
Expand Down Expand Up @@ -68,8 +68,7 @@ def report_progress(
``report`` lines are written into it.
"""

timestamp = tmt.steps.execute.ExecutePlugin.format_timestamp(
datetime.datetime.now(datetime.timezone.utc))
timestamp = format_timestamp(datetime.datetime.now(datetime.timezone.utc))

with open(log, mode='a') as f:
f.write(f'# {check_name} reported at {timestamp}\n')
Expand Down
38 changes: 17 additions & 21 deletions tmt/steps/execute/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import copy
import dataclasses
import datetime
import functools
import json
import os
Expand All @@ -27,7 +26,14 @@
from tmt.steps import Action, ActionTask, PhaseQueue, PluginTask, Step
from tmt.steps.discover import Discover, DiscoverPlugin, DiscoverStepData
from tmt.steps.provision import Guest
from tmt.utils import Path, ShellScript, Stopwatch, field
from tmt.utils import (
Path,
ShellScript,
Stopwatch,
field,
format_duration,
format_timestamp,
)

if TYPE_CHECKING:
import tmt.cli
Expand Down Expand Up @@ -904,23 +910,13 @@ def extract_results(

return invocation.test.test_framework.extract_results(invocation, logger)

@staticmethod
def format_timestamp(timestamp: datetime.datetime) -> str:
""" Convert timestamp to a human readable format """

return timestamp.isoformat()

@staticmethod
def format_duration(duration: datetime.timedelta) -> str:
""" Convert duration to a human readable format """

# A helper variable to hold the duration while we cut away days, hours and seconds.
counter = int(duration.total_seconds())

hours, counter = divmod(counter, 3600)
minutes, seconds = divmod(counter, 60)
def check_abort_file(self, invocation: TestInvocation) -> bool:
"""
Check for an abort file created by tmt-abort
return f'{hours:02}:{minutes:02}:{seconds:02}'
Returns whether an abort file is present (i.e. abort occurred).
"""
return (invocation.test_data_path / TMT_ABORT_SCRIPT.created_file).exists()

def timeout_hint(self, invocation: TestInvocation) -> None:
""" Append a duration increase hint to the test output """
Expand Down Expand Up @@ -957,9 +953,9 @@ def _run_checks_for_test(
for result in check_results:
result.event = event

result.start_time = self.format_timestamp(timer.start_time)
result.end_time = self.format_timestamp(timer.end_time)
result.duration = self.format_duration(timer.duration)
result.start_time = format_timestamp(timer.start_time)
result.end_time = format_timestamp(timer.end_time)
result.duration = format_duration(timer.duration)

results += check_results

Expand Down
8 changes: 5 additions & 3 deletions tmt/steps/execute/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
ShellScript,
Stopwatch,
field,
format_duration,
format_timestamp,
)

TEST_PIDFILE_FILENAME = 'tmt-test.pid'
Expand Down Expand Up @@ -387,7 +389,7 @@ def _save_process(

# Execute the test, save the output and return code
with Stopwatch() as timer:
invocation.start_time = self.format_timestamp(timer.start_time)
invocation.start_time = format_timestamp(timer.start_time)

timeout: Optional[int]

Expand Down Expand Up @@ -429,8 +431,8 @@ def _save_process(
with invocation.process_lock:
invocation.process = None

invocation.end_time = self.format_timestamp(timer.end_time)
invocation.real_duration = self.format_duration(timer.duration)
invocation.end_time = format_timestamp(timer.end_time)
invocation.real_duration = format_duration(timer.duration)

# Save the captured output. Do not let the follow-up pulls
# overwrite it.
Expand Down
18 changes: 18 additions & 0 deletions tmt/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6375,6 +6375,24 @@ def duration(self) -> datetime.timedelta:
return self.end_time - self.start_time


def format_timestamp(timestamp: datetime.datetime) -> str:
""" Convert timestamp to a human readable format """

return timestamp.isoformat()


def format_duration(duration: datetime.timedelta) -> str:
""" Convert duration to a human readable format """

# A helper variable to hold the duration while we cut away days, hours and seconds.
counter = int(duration.total_seconds())

hours, counter = divmod(counter, 3600)
minutes, seconds = divmod(counter, 60)

return f'{hours:02}:{minutes:02}:{seconds:02}'


def retry(
func: Callable[..., T],
attempts: int,
Expand Down

0 comments on commit db6604b

Please sign in to comment.