Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

permissions:
contents: read
Expand Down
9 changes: 6 additions & 3 deletions tests/perf/test_ux_budgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def test_cached_ready_run_submit_is_one_preflight_one_upload_and_one_submit(
assert fake_transport.call_counts["exec"] == 0


def test_query_and_render_one_thousand_runs_has_sub_500ms_median(ctx) -> None:
def test_query_and_render_one_thousand_runs_has_sub_500ms_cpu_median(ctx) -> None:
database = ctx.db()
repository = RunRepo(database)
resources = Resources()
Expand Down Expand Up @@ -225,14 +225,17 @@ def render_once() -> float:
),
Console(file=StringIO()),
)
started = time.perf_counter()
# Keep this CPU regression budget independent of pauses introduced by
# shared CI runner scheduling while still catching slower query and
# rendering work.
started = time.process_time()
rows = RunService(ctx).list_views()
output.records(
"Runs",
["RUN", "STATE", "TASKS", "JOB", "CREATED"],
[[row.id, row.state, row.summary.format_counts(), row.slurm_job_id or "-", row.created_at] for row in rows],
)
return time.perf_counter() - started
return time.process_time() - started

render_once()
durations = [render_once() for _ in range(7)]
Expand Down
4 changes: 3 additions & 1 deletion tests/tui/test_pilot.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,9 @@ async def test_gc_previews_before_deleting(self, ctx, remote_root):
await pilot.press("2")
await _wait_for(lambda: isinstance(app.screen, EnvsScreen))
await pilot.press("g")
await _wait_for(lambda: isinstance(app.screen, ConfirmModal))
await pilot.pause()
assert isinstance(app.screen, ConfirmModal)
app.screen.query_one("#yes")
assert candidate.exists()
await pilot.click("#yes")
await _wait_for(lambda: not candidate.exists())
Expand Down
14 changes: 12 additions & 2 deletions tests/unit/test_env_executors.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@ def _prepare(
)


def _wait_for_process_exit(pid: int, *, timeout: float = 5.0) -> None:
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
try:
os.kill(pid, 0)
except OSError:
return
time.sleep(0.05)
pytest.fail(f"background process {pid} did not exit within {timeout:.1f}s")
Comment on lines +141 to +149


class TestSlurmEnvironmentExecutor:
def test_failed_build_helper_exits_nonzero_so_afterok_cannot_release(
self,
Expand Down Expand Up @@ -543,8 +554,7 @@ def test_background_login_build_has_pid_heartbeat_receipt_and_no_resubmit_on_unk
assert reconciled.status is EnvironmentStatus.READY
assert reconciled.active_generation == attempt.generation_id
assert protocol.JSON_PREFIX not in Path(attempt.stdout_path).read_text(encoding="utf-8")
with pytest.raises(OSError):
os.kill(attempt.login_pid, 0)
_wait_for_process_exit(attempt.login_pid)


class TestExistingEnvironmentVerification:
Expand Down