• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from __future__ import annotations
6
7import abc
8import contextlib
9import logging
10from collections.abc import Generator
11from typing import TYPE_CHECKING, Iterable, Tuple
12
13from crossbench import plt
14from crossbench.helper import DurationMeasureContext, Durations
15from crossbench.probes.result_location import ResultLocation
16
17if TYPE_CHECKING:
18  from crossbench.browsers.browser import Browser
19  from crossbench.exception import (Annotator, ExceptionAnnotationScope,
20                                    TExceptionTypes)
21  from crossbench.path import AnyPath, LocalPath
22  from crossbench.probes.probe import Probe
23  from crossbench.runner.runner import Runner
24
25
26class ResultOrigin(abc.ABC):
27  """Base class for Run and BrowserSession, both places where
28  probe results can be placed."""
29
30  @property
31  def is_local(self) -> bool:
32    return self.browser_platform.is_local
33
34  @property
35  def is_remote(self) -> bool:
36    return self.browser_platform.is_remote
37
38  @property
39  @abc.abstractmethod
40  def browser_tmp_dir(self) -> AnyPath:
41    pass
42
43  @property
44  @abc.abstractmethod
45  def out_dir(self) -> LocalPath:
46    pass
47
48  @property
49  @abc.abstractmethod
50  def exceptions(self) -> Annotator:
51    pass
52
53  @property
54  @abc.abstractmethod
55  def durations(self) -> Durations:
56    pass
57
58  @property
59  @abc.abstractmethod
60  def browser(self) -> Browser:
61    pass
62
63  @property
64  def runner(self) -> Runner:
65    raise NotImplementedError(
66        f"Cannot access on runner on {type(self).__name__}")
67
68  @property
69  def host_platform(self) -> plt.Platform:
70    return self.browser.host_platform
71
72  @property
73  def browser_platform(self) -> plt.Platform:
74    return self.browser.platform
75
76  @property
77  def probes(self) -> Iterable[Probe]:
78    # TODO: migrate away from using runner
79    return self.runner.probes
80
81  @contextlib.contextmanager
82  def measure(
83      self, label: str
84  ) -> Generator[Tuple[ExceptionAnnotationScope, DurationMeasureContext], None,
85                 None]:
86    # Return a combined context manager that adds an named exception info
87    # and measures the time during the with-scope.
88    with self.exceptions.info(label) as stack, self.durations.measure(
89        label) as timer:
90      yield (stack, timer)
91
92  def exception_info(self, *stack_entries: str) -> ExceptionAnnotationScope:
93    return self.exceptions.info(*stack_entries)
94
95  def exception_handler(
96      self, *stack_entries: str, exceptions: TExceptionTypes = (Exception,)
97  ) -> ExceptionAnnotationScope:
98    return self.exceptions.capture(*stack_entries, exceptions=exceptions)
99
100  def get_default_probe_result_path(self, probe: Probe) -> AnyPath:
101    """Return a local or remote/browser-based result path depending on the
102    Probe default RESULT_LOCATION."""
103    if probe.RESULT_LOCATION == ResultLocation.BROWSER:
104      return self.get_browser_probe_result_path(probe)
105    if probe.RESULT_LOCATION == ResultLocation.LOCAL:
106      return self.get_local_probe_result_path(probe)
107    raise ValueError(f"Invalid probe.RESULT_LOCATION {probe.RESULT_LOCATION} "
108                     f"for probe {probe}")
109
110  @abc.abstractmethod
111  def get_local_probe_result_path(self, probe: Probe) -> LocalPath:
112    pass
113
114  def get_browser_probe_result_path(self, probe: Probe) -> AnyPath:
115    local_path = self.get_local_probe_result_path(probe)
116    if self.is_local:
117      return local_path
118    # Create a temp file relative to the remote browser tmp dir.
119    relative_path = local_path.relative_to(self.out_dir)
120    path = self.browser_tmp_dir / relative_path
121    logging.debug("Creating remote result dir=%s on platform=%s", path.parent,
122                  self.browser_platform)
123    self.browser_platform.mkdir(path.parent)
124    return path
125