dev/e2e: wall_clock regression check + deterministic fixture dates
`e2e.sh check` compares every indexed fixture's manifest wall clock with the `wall_clock` reported by /image/metadata, /memories and /photos/gps-summary; any disagreement fails. - Fixture videos are stamped like phone containers: the America/New_York wall as a UTC creation_time (the label previously showed the UTC time). - mtimes are pinned in America/New_York instead of the host's zone. - The e2e env sets TZ=America/New_York (the #120 preflight): the Windows exe has no /etc/timezone, so server_zone() was otherwise None. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e2f33684c8
commit
bc41c737e5
4 files changed
+97
-5
No files matched your search
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regression check for the displayed capture time (ADR-0001 `wall_clock`).
|
||||
|
||||
For every indexed fixture, the manifest's expected wall clock must equal the
|
||||
`wall_clock` the server reports on each endpoint that includes the file:
|
||||
`/image/metadata`, `/memories` (today's day span) and `/photos/gps-summary`.
|
||||
One disagreement anywhere is exactly the class of bug this field exists to
|
||||
end, so any mismatch fails the run.
|
||||
|
||||
Usage: check_wall_clock.py <manifest.json> (run via `e2e.sh check`)
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
|
||||
E2E = Path(__file__).with_name("e2e.sh")
|
||||
|
||||
|
||||
def api(path: str) -> dict:
|
||||
return json.loads(subprocess.check_output([str(E2E), "api", "GET", path]))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
manifest = json.load(open(sys.argv[1]))
|
||||
excluded = tuple(d.strip("/") + "/" for d in manifest["excluded_dirs"])
|
||||
items = [i for i in manifest["items"] if not i["path"].startswith(excluded)]
|
||||
|
||||
memories = {m["path"]: m.get("wall_clock") for m in api("memories?span=day")["items"]}
|
||||
gps = {g["path"]: g.get("wall_clock") for g in api("photos/gps-summary?path=")["photos"]}
|
||||
|
||||
failures = 0
|
||||
for item in items:
|
||||
path, want = item["path"], item["wall_clock"]
|
||||
got = {"metadata": api("image/metadata?path=" + urllib.parse.quote(path)).get("wall_clock")}
|
||||
if path in memories:
|
||||
got["memories"] = memories[path]
|
||||
if path in gps:
|
||||
got["gps-summary"] = gps[path]
|
||||
bad = {k: v for k, v in got.items() if v != want}
|
||||
if bad:
|
||||
failures += 1
|
||||
print(f"MISMATCH {path}: expected {want}, got {bad}")
|
||||
|
||||
print(f"{len(items) - failures}/{len(items)} fixtures report the expected wall clock "
|
||||
f"({len(memories)} in memories, {len(gps)} in gps-summary)")
|
||||
return 1 if failures else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("E2E_TOKEN", subprocess.check_output([str(E2E), "token"], text=True).strip())
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user