"""Ansible runs are named by what ran where, say how long ago and for how long, and wear the one status badge every page uses (#5125).""" from datetime import datetime, timedelta, timezone from types import SimpleNamespace import pytest from quart import render_template, session from steward.ansible.inventory_gen import run_title from steward.ansible.routes import run_duration, run_view from steward.models.ansible import AnsibleRunStatus from tests.test_style_tokens import hex_colours @pytest.mark.parametrize("label, title", [ ("target web-1", "update.yml on web-1"), ("group Docker Swarm", "update.yml on group Docker Swarm"), ("all inventory targets", "update.yml on all inventory targets"), ("homelab/hosts.ini", "update.yml on homelab/hosts.ini"), ("", "update.yml"), ]) def test_a_run_is_named_by_what_ran_where(label, title): assert run_title("update.yml", label) == title def _run(rid, status, started_min_ago, took_s=None, scope="steward:target:t1", check=False): now = datetime.now(timezone.utc) started = now - timedelta(minutes=started_min_ago) return SimpleNamespace( id=rid, playbook_path="update.yml", source_name="builtin", inventory_scope=scope, status=status, started_at=started, finished_at=started + timedelta(seconds=took_s) if took_s is not None else None, params={"check": True} if check else None, results=None, output="") def test_a_running_run_counts_its_duration_so_far(): now = datetime.now(timezone.utc) run = _run("r", AnsibleRunStatus.running, 3) assert run_duration(run, now) == pytest.approx(180, abs=2) assert run_duration(_run("f", AnsibleRunStatus.success, 10, took_s=95), now) == 95 async def test_the_runs_list_names_each_run_with_one_badge(app): now = datetime.now(timezone.utc) labels = {"steward:target:t1": "target web-1", "steward:all": "all inventory targets"} runs = [run_view(r, labels, now) for r in ( _run("aaaa1111", AnsibleRunStatus.running, 2), _run("bbbb2222", AnsibleRunStatus.failed, 60, took_s=125, scope="steward:all", check=True), _run("cccc3333", AnsibleRunStatus.success, 120, took_s=40), )] async with app.test_request_context("/ansible/"): session["user_role"] = "viewer" page = await render_template("ansible/index.html", runs=runs) main = page[page.index("update.yml on web-1' in main assert ">update.yml on all inventory targets" in main assert 'Running' in main assert 'Failed' in main assert 'Succeeded' in main assert "2m 5s" in main and "40s" in main and " so far" in main assert "dry run" in main and "ago" in main assert "RUNNING" not in main and "FAILED" not in main # the old shouted status text is gone assert not hex_colours(main), hex_colours(main) async def test_run_detail_titles_the_run_and_keeps_the_trail(app): now = datetime.now(timezone.utc) run = _run("dddd4444", AnsibleRunStatus.interrupted, 30, took_s=600) async with app.test_request_context("/ansible/runs/dddd4444"): session["user_role"] = "operator" page = await render_template("ansible/run_detail.html", run=run, triggered_label="system", row=run_view(run, {"steward:target:t1": "target web-1"}, now)) assert "update.yml on web-1 — Steward" in page assert 'href="/ansible/"' in page # breadcrumb back to the runs assert 'Interrupted' in page assert "
10m
" in page assert "/cancel" not in page # an interrupted run has nothing to cancel main = page[page.index("Running' in page assert "update.yml on web-1" in page and 'href="/ansible/runs/eeee5555"' in page assert not hex_colours(page), hex_colours(page)