feat: add performance controls for large browser ops

- Add throttled large-operation handling for tab, group, and session commands.
- Introduce performance profiles, audible-tab aware gentle mode, and job progress tracking.
- Support background session restores with status/cancel commands and lazy placeholders.
- Expose new perf and extension CLI groups plus matching Python SDK methods.
- Preserve pinned tabs during session snapshots and debounce auto-save updates.
- Bump browser-cli and extension versions to 0.10.0 and add pytest-cov to dev deps.
- Add coverage for performance controls, background jobs, lazy restores, and tab metadata.
This commit is contained in:
2026-05-20 22:13:57 +02:00
parent e1e4adbb25
commit 545abeb515
18 changed files with 1054 additions and 148 deletions
+157
View File
@@ -0,0 +1,157 @@
"""Integration tests for browser performance controls and background jobs."""
import time
import uuid
import pytest
def _wait_for_job(browser, job_id, timeout=10):
deadline = time.time() + timeout
last = None
while time.time() < deadline:
last = browser("jobs.status", {"jobId": job_id})
if last.get("status") in {"done", "error", "cancelled"}:
return last
time.sleep(0.1)
return last or {}
def _close_tabs(browser, tab_ids):
for tab_id in tab_ids:
try:
browser("tabs.close", {"tabId": tab_id})
except Exception:
pass
def _require_perf_features(browser):
try:
return browser("perf.status", {})
except RuntimeError as exc:
if "Unknown command: perf.status" in str(exc):
pytest.skip("Running browser has not reloaded the v0.10.0 extension background worker yet")
raise
def test_perf_status_and_profile_roundtrip_real_browser(browser):
initial = _require_perf_features(browser)
assert "performanceProfile" in initial
assert "audible" in initial
assert "throttle" in initial
assert "jobs" in initial
original = initial.get("performanceProfile", "auto")
try:
changed = browser("perf.set_profile", {"profile": "gentle"})
assert changed["performanceProfile"] == "gentle"
status = browser("perf.status", {})
assert status["performanceProfile"] == "gentle"
assert status["throttle"]["mode"] == "gentle"
finally:
browser("perf.set_profile", {"profile": original})
def test_background_session_load_job_reports_progress_real_browser(browser):
_require_perf_features(browser)
name = f"_pytest_perf_job_{uuid.uuid4().hex}"
marker_url = f"https://example.com/?browser-cli-job={uuid.uuid4().hex}"
marker_tab = browser("navigate.open", {"url": marker_url, "background": True})
loaded_ids = set()
try:
browser("session.save", {"name": name})
baseline_ids = {tab["id"] for tab in browser("tabs.list")}
started = browser("session.load", {
"name": name,
"__background": True,
"lazy": True,
"eagerTabs": 0,
"gentleMode": "ultra",
})
assert started["status"] == "running"
assert started["jobId"]
status = _wait_for_job(browser, started["jobId"])
assert status["status"] == "done"
assert status["command"] == "session.load"
assert status["percent"] == 100
assert status["phase"] == "done"
assert status["total"] is None or status["total"] >= 0
assert status.get("result", {}).get("lazy") is True
loaded_ids = {tab["id"] for tab in browser("tabs.list")} - baseline_ids
assert loaded_ids, "Expected lazy session load to create tabs"
finally:
_close_tabs(browser, loaded_ids)
_close_tabs(browser, [marker_tab["id"]])
try:
browser("session.remove", {"name": name})
except Exception:
pass
def test_lazy_session_load_creates_lightweight_placeholders_real_browser(browser):
_require_perf_features(browser)
name = f"_pytest_lazy_{uuid.uuid4().hex}"
marker_url = f"https://example.com/?browser-cli-lazy={uuid.uuid4().hex}"
marker_tab = browser("navigate.open", {"url": marker_url, "background": True})
loaded_ids = set()
try:
browser("session.save", {"name": name})
baseline_ids = {tab["id"] for tab in browser("tabs.list")}
result = browser("session.load", {"name": name, "lazy": True, "eagerTabs": 0, "gentleMode": "ultra"})
assert result["lazy"] is True
assert result["eagerTabs"] == 0
tabs_after = browser("tabs.list")
loaded_tabs = [tab for tab in tabs_after if tab["id"] not in baseline_ids]
loaded_ids = {tab["id"] for tab in loaded_tabs}
assert loaded_tabs
assert any((tab.get("url") or "").startswith("data:text/html") for tab in loaded_tabs)
finally:
_close_tabs(browser, loaded_ids)
_close_tabs(browser, [marker_tab["id"]])
try:
browser("session.remove", {"name": name})
except Exception:
pass
def test_session_load_restores_pinned_tabs_real_browser(browser):
_require_perf_features(browser)
name = f"_pytest_pinned_{uuid.uuid4().hex}"
marker_url = f"https://example.com/?browser-cli-pinned={uuid.uuid4().hex}"
marker_tab = browser("navigate.open", {"url": marker_url, "background": True})
loaded_ids = set()
try:
browser("tabs.pin", {"tabId": marker_tab["id"]})
browser("session.save", {"name": name})
baseline_ids = {tab["id"] for tab in browser("tabs.list")}
result = browser("session.load", {"name": name, "gentleMode": "ultra", "discardBackgroundTabs": True})
assert result["tabs"] >= 1
loaded_tabs = [tab for tab in browser("tabs.list") if tab["id"] not in baseline_ids]
loaded_ids = {tab["id"] for tab in loaded_tabs}
matching = [tab for tab in loaded_tabs if tab.get("url") == marker_url]
assert matching, "Expected session load to restore marker tab"
assert matching[0].get("pinned") is True
finally:
_close_tabs(browser, loaded_ids)
_close_tabs(browser, [marker_tab["id"]])
try:
browser("session.remove", {"name": name})
except Exception:
pass
def test_job_cancel_command_real_browser(browser):
_require_perf_features(browser)
started = browser("tabs.sort", {"by": "domain", "__background": True, "gentleMode": "ultra"})
job_id = started["jobId"]
try:
cancelled = browser("jobs.cancel", {"jobId": job_id})
assert cancelled["cancelled"] is True
except RuntimeError:
# Tiny real-browser sorts can finish before the cancel request arrives.
status = browser("jobs.status", {"jobId": job_id})
assert status["status"] in {"done", "cancelled"}
return
status = _wait_for_job(browser, job_id)
assert status["status"] in {"cancelled", "done"}