blob: affeedcef371574816a6fd4482cd3e18b9f322bf [file] [log] [blame] [edit]
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import annotations
import abc
import datetime as dt
import logging
from typing import TYPE_CHECKING, Sequence
from crossbench.path import safe_filename
if TYPE_CHECKING:
from crossbench.runner.run import Run
from crossbench.types import JsonDict
class Story(abc.ABC):
@classmethod
@abc.abstractmethod
def all_story_names(cls) -> Sequence[str]:
pass
def __init__(self,
name: str,
duration: dt.timedelta = dt.timedelta(seconds=15)):
assert name, "Invalid page name"
self._name = safe_filename(name)
self._duration = duration
if self._duration:
assert self._duration.total_seconds() > 0, (
f"Duration must be non-empty, but got: {duration}")
@property
def name(self) -> str:
return self._name
@property
def duration(self) -> dt.timedelta:
return self._duration
def details_json(self) -> JsonDict:
return {"name": self.name, "duration": self.duration.total_seconds()}
def log_run_details(self, run: Run) -> None:
logging.info("STORY: %s", self)
timing = run.timing
logging.info("STORY DURATION: expected=%s timeout=%s",
timing.timedelta(self.duration),
timing.timeout_timedelta(self.duration))
def setup(self, run: Run) -> None:
"""Setup work for a story that is not part of the main workload should
be put in this method. Probes can skip measuring this section.
i.e selecting substories to run.
"""
@abc.abstractmethod
def run(self, run: Run) -> None:
"""The main workload of a story that is measured by all Probes.
"""
def teardown(self, run: Run) -> None:
"""Cleanup work for a story that is not part of the main workload should
be put in this method. Probes can skip measuring this section.
"""
def __str__(self) -> str:
return f"Story(name={self.name})"