"""Integration: the Ansible Runs tab (#5329) and the Inventory page (#5333)
against real Postgres. The Runs tab's
verdict counts the last 30 days; the filter bar narrows by playbook, status
and origin; an HTMX request from the bar gets the table alone, and the next
page as the reader scrolls keeps the filters. Requires STEWARD_DATABASE_URL."""
from __future__ import annotations
import asyncio
import os
import time
import uuid
from datetime import datetime, timedelta, timezone
import pytest
pytestmark = pytest.mark.integration
@pytest.fixture
def app():
if not os.environ.get("STEWARD_DATABASE_URL"):
pytest.skip("needs Postgres")
from steward.app import create_app
return create_app(testing=False)
def test_the_runs_tab_counts_and_filters(app):
from steward.models.ansible import AnsibleRun, AnsibleRunStatus
from steward.models.users import User, UserRole
async def _go():
tag = uuid.uuid4().hex[:8]
uid = str(uuid.uuid4())
now = datetime.now(timezone.utc)
def run(name, status, mins, origin=None, by=None, results=None):
return AnsibleRun(playbook_path=f"it{tag}/{name}.yml", source_name="steward-builtin",
inventory_scope="steward:all", status=status, origin=origin,
triggered_by=by, started_at=now - timedelta(minutes=mins),
finished_at=now - timedelta(minutes=mins - 1), results=results)
async with app.db_sessionmaker() as s:
async with s.begin():
s.add(User(id=uid, username=f"runs-{tag}", email=f"runs-{tag}@test",
password_hash="x", role=UserRole.viewer, is_active=True))
async with s.begin():
s.add_all([
run("prune", AnsibleRunStatus.success, 10, origin="schedule",
results={"hosts": {"a": {"ok": 2, "changed": 1}, "b": {"ok": 2, "changed": 1}}}),
run("update", AnsibleRunStatus.failed, 20, by=uid,
results={"hosts": {f"db-{tag}": {"ok": 1, "failed": 1}}}),
])
client = app.test_client()
async with client.session_transaction() as sess:
sess.update(user_id=uid, user_role="viewer", username=f"runs-{tag}", login_at=time.time())
async def get(url, **kw):
resp = await client.get(url, **kw)
return resp.status_code, await resp.get_data(as_text=True)
out = {"page": await get(f"/ansible/?q=it{tag}"),
"failed": await get(f"/ansible/?q=it{tag}&status=failed", headers={"HX-Request": "true"}),
"sched": await get(f"/ansible/?q=it{tag}&origin=schedule", headers={"HX-Request": "true"}),
"person": await get(f"/ansible/?q=it{tag}&origin=manual", headers={"HX-Request": "true"}),
# The Playbooks tab and a built-in playbook's page (#5331): their
# newest-run and schedule queries against Postgres.
"playbooks": await get("/ansible/playbooks"),
"playbook": await get("/ansible/playbooks/steward-builtin/maintenance/docker_prune.yml"),
"missing": await get("/ansible/playbooks/steward-builtin/nope.yml")}
async with app.db_sessionmaker() as s:
async with s.begin():
from sqlalchemy import delete
await s.execute(delete(AnsibleRun).where(AnsibleRun.playbook_path.like(f"it{tag}/%")))
await s.delete(await s.get(User, uid))
return tag, out
tag, out = asyncio.run(_go())
status, page = out["page"]
assert status == 200
assert '
' in page and "in the last 30 days" in page # the verdict queries ran
assert f"it{tag}/prune.yml" in page and f"it{tag}/update.yml" in page
assert "2 hosts ยท 2 changed" in page and f'failed on db-{tag}' in page
assert '