| # 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 html |
| import urllib.parse |
| from argparse import ArgumentTypeError |
| from typing import TYPE_CHECKING, Any, Dict |
| |
| from crossbench import path as pth |
| |
| if TYPE_CHECKING: |
| from crossbench.runner.run import Run |
| |
| |
| class SplashScreen: |
| NONE: SplashScreen |
| MINIMAL: SplashScreen |
| DETAILED: SplashScreen |
| DEFAULT: SplashScreen |
| |
| @classmethod |
| def parse(cls, value: str) -> SplashScreen: |
| if not value or value == "default": |
| return cls.DEFAULT |
| if value in ("none", "skip"): |
| return cls.NONE |
| if value == "minimal": |
| return cls.MINIMAL |
| if value == "detailed": |
| return cls.DETAILED |
| if value.startswith("http:") or value.startswith("https:"): |
| return URLSplashScreen(value) |
| maybe_path = pth.LocalPath(value) |
| if maybe_path.exists(): |
| return URLSplashScreen(maybe_path.absolute().as_uri()) |
| raise ArgumentTypeError(f"Unknown splashscreen: {value}") |
| |
| def run(self, run: Run) -> None: |
| pass |
| |
| |
| _BLANK_PAGE_HTML = "<html></html>" |
| _BLANK_PAGE_DATA_URL = ( |
| f"data:text/html;charset=utf-8,{urllib.parse.quote(_BLANK_PAGE_HTML)}") |
| |
| |
| class BaseURLSplashScreen(SplashScreen, metaclass=abc.ABCMeta): |
| |
| def __init__(self, timeout: float = 2) -> None: |
| super().__init__() |
| self._timeout = timeout |
| |
| def run(self, run: Run) -> None: |
| with run.actions("SplashScreen") as action: |
| action.show_url(self.get_url(run)) |
| action.wait(self._timeout) |
| action.show_url(_BLANK_PAGE_DATA_URL) |
| |
| @abc.abstractmethod |
| def get_url(self, run: Run) -> str: |
| pass |
| |
| |
| class DetailedSplashScreen(BaseURLSplashScreen): |
| |
| def get_url(self, run: Run) -> str: |
| browser = run.browser |
| title = html.escape(browser.app_name.title()) |
| version = html.escape(browser.version) |
| run_type = "Run" |
| bg_color = "#000" |
| if run.is_warmup: |
| title = f"Warmup: {title}" |
| run_type = "Warmup Run" |
| bg_color = "#444" |
| page = "".join(( |
| "<html><head>" |
| f"<title>{run_type} Details</title>", |
| "<style>", |
| "html{" |
| "font-family:sans-serif;", |
| f"background-color:{bg_color};", |
| "color:#fff", |
| "}", |
| "dl{display:grid;grid-template-columns:max-content auto}", |
| "dt{grid-column-start:1}", |
| "dd{grid-column-start:2;font-family:monospace}", |
| "</style>", |
| "</head><body>", |
| f"<h1>{title} {version}</h1>", |
| self._render_browser_details(run), |
| self._render_run_details(run), |
| "</body></html>", |
| )) |
| data_url = f"data:text/html;charset=utf-8,{urllib.parse.quote(page)}" |
| return data_url |
| |
| def _render_properties(self, title: str, properties: Dict[str, Any]) -> str: |
| section = f"<h2>{html.escape(title)}</h2><dl>" |
| for property_name, value in properties.items(): |
| section += f"<dt>{html.escape(property_name)}</dt>" |
| section += f"<dd>{html.escape(str(value))}</dd>" |
| section += "</dl>" |
| return section |
| |
| def _render_browser_details(self, run: Run) -> str: |
| browser = run.browser |
| properties = { |
| "User Agent": browser.user_agent(run.runner), |
| **browser.details_json() |
| } |
| return self._render_properties("Browser Details", properties) |
| |
| def _render_run_details(self, run: Run) -> str: |
| return self._render_properties("Run Details", run.details_json()) |
| |
| |
| class MinimalSplashScreen(DetailedSplashScreen): |
| |
| def _render_browser_details(self, run: Run) -> str: |
| properties = {"User Agent": run.browser.user_agent(run.runner)} |
| return self._render_properties("Browser Details", properties) |
| |
| |
| class URLSplashScreen(BaseURLSplashScreen): |
| |
| def __init__(self, url: str, timeout: float = 2) -> None: |
| super().__init__(timeout) |
| self._url = url |
| |
| def get_url(self, run: Run) -> str: |
| return self._url |
| |
| @property |
| def url(self) -> str: |
| return self._url |
| |
| |
| SplashScreen.NONE = SplashScreen() |
| SplashScreen.MINIMAL = MinimalSplashScreen() |
| SplashScreen.DETAILED = DetailedSplashScreen() |
| SplashScreen.DEFAULT = SplashScreen.DETAILED |