Verified Commit 0c9c4a14 authored by Sebastian Endres's avatar Sebastian Endres
Browse files

Add image versions (=metadata) support

parent 57cc73d9
......@@ -12,6 +12,8 @@ from itertools import chain
from pathlib import Path
from typing import Literal, Optional, TypedDict, Union, cast
from dateutil.parser import parse as parse_date
from utils import UrlOrPath
DETAILS_RE = re.compile(r"(?P<avg>\d+) \(± (?P<var>\d+)\) (?P<unit>\w+)")
......@@ -53,6 +55,15 @@ class RawMeasurement(TypedDict):
details: str
class RawImageInfo(TypedDict):
"""A info about an image."""
image: str
id: str
versions: list[str]
created: Optional[str]
class RawResult(TypedDict):
"""The unmodified content of result.json."""
......@@ -62,6 +73,7 @@ class RawResult(TypedDict):
servers: list[str]
clients: list[str]
urls: dict[str, str]
versions: Optional[dict[str, RawImageInfo]]
tests: dict[str, Union[RawTestDescr, RawMeasurementDescr]]
quic_draft: int
quic_version: str
......@@ -85,6 +97,10 @@ class Implementation:
url: str
role: ImplementationRole
image_id: Optional[str] = None
versions: Optional[list[str]] = None
created: Optional[datetime] = None
@dataclass(frozen=True)
class TestDescription:
......@@ -358,12 +374,22 @@ class Result:
def log_dir(self, value: UrlOrPath):
self.raw_data["log_dir"] = str(value)
def get_image_info(
self, impl: Union[str, Implementation]
) -> Union[RawImageInfo, dict]:
versions = self.raw_data.get("versions", {}) or {}
impl_name = impl if isinstance(impl, str) else impl.name
return versions.get(impl_name, {})
def _update_implementations(
self, value: list[Implementation], role: ImplementationRole
):
assert role != ImplementationRole.BOTH
for impl in value:
img_info = self.get_image_info(impl.name)
if impl.name not in self.raw_data["urls"]:
self.raw_data["urls"][impl.name] = impl.url
elif impl.url != self.raw_data["urls"][impl.name]:
......@@ -371,6 +397,11 @@ class Result:
"There are two different urls for implementation "
f"{impl.url} and {self.raw_data['urls'][impl.name]}"
)
elif impl.image_id and "id" in img_info and impl.image_id != img_info["id"]:
raise ValueError(
f"There current image ID of {impl.name} differs from the image ID "
f"used in the other run: {impl.image_id} != {img_info['id']}"
)
list_key: Union[Literal["servers"], Literal["clients"]] = (
"servers" if role == ImplementationRole.SERVER else "clients"
......@@ -383,22 +414,43 @@ class Result:
self._implementations_changed = True
self.raw_data[list_key].append(impl.name)
def _get_implementations(self, role: ImplementationRole) -> list[Implementation]:
assert role != ImplementationRole.BOTH
ret = list[Implementation]()
lookup = (
self.raw_data["clients"]
if role == ImplementationRole.CLIENT
else self.raw_data["servers"]
)
lookup_other = (
self.raw_data["servers"]
if role == ImplementationRole.CLIENT
else self.raw_data["clients"]
)
for name in lookup:
versions = self.raw_data.get("versions") or {}
img_info = versions.get(name, {})
created_raw: Optional[str] = img_info.get("created")
created = parse_date(created_raw) if created_raw else None
ret.append(
Implementation(
name=name,
url=self.raw_data["urls"][name],
role=ImplementationRole.BOTH if name in lookup_other else role,
image_id=img_info.get("id"),
versions=img_info.get("versions"),
created=created,
)
)
return ret
@property
def servers(self) -> list[Implementation]:
"""The list of servers with metadata used in this test run."""
return [
Implementation(
name=name,
url=self.raw_data["urls"][name],
role=(
ImplementationRole.BOTH
if name in self.raw_data["clients"]
else ImplementationRole.SERVER
),
)
for name in self.raw_data["servers"]
]
return self._get_implementations(ImplementationRole.SERVER)
@servers.setter
def servers(self, value: list[Implementation]):
......@@ -408,18 +460,7 @@ class Result:
def clients(self) -> list[Implementation]:
"""The list of clients with metadata used in this test run."""
return [
Implementation(
name=name,
url=self.raw_data["urls"][name],
role=(
ImplementationRole.BOTH
if name in self.raw_data["servers"]
else ImplementationRole.CLIENT
),
)
for name in self.raw_data["clients"]
]
return self._get_implementations(ImplementationRole.CLIENT)
@clients.setter
def clients(self, value: list[Implementation]):
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment