WS1: Add 8 extended seed-demo tests (cluster, deadlines, red flags, suggestions, notifications, telemetry, artifacts)
This commit is contained in:
parent
71a16d35ed
commit
ba51a00f2b
1 changed files with 115 additions and 3 deletions
|
|
@ -279,14 +279,22 @@ class TestInterviewPrep:
|
||||||
|
|
||||||
class TestSeedDemo:
|
class TestSeedDemo:
|
||||||
def test_seed_demo_creates_data(self, client):
|
def test_seed_demo_creates_data(self, client):
|
||||||
"""POST /concierge/seed-demo creates profile, postings, applications."""
|
"""POST /concierge/seed-demo creates profile, postings, applications, and extended data."""
|
||||||
resp = client.post("/api/concierge/seed-demo")
|
resp = client.post("/api/concierge/seed-demo")
|
||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
assert data["profile"] == "Demo Demosson"
|
assert data["profile"] == "Demo Demosson"
|
||||||
assert data["postings"] == 6
|
|
||||||
assert data["applications"] == 6
|
|
||||||
assert data["sections"] == 4
|
assert data["sections"] == 4
|
||||||
|
# 6 standalone + 3 agency + 2 deadline + 1 redflag + 1 interviewing = 13 postings
|
||||||
|
assert data["postings"] == 13
|
||||||
|
# 6 standalone + 3 agency + 2 deadline + 1 redflag + 1 interviewing = 13 applications
|
||||||
|
assert data["applications"] == 13
|
||||||
|
assert data["clusters"] >= 1
|
||||||
|
assert data["deadlines"] >= 2
|
||||||
|
assert data["suggestions"] == 2
|
||||||
|
assert data["notifications"] == 3
|
||||||
|
assert data["task_runs"] == 6
|
||||||
|
assert data["cv_artifacts"] >= 1
|
||||||
|
|
||||||
def test_seed_demo_idempotent(self, client):
|
def test_seed_demo_idempotent(self, client):
|
||||||
"""Running seed-demo twice returns the same counts."""
|
"""Running seed-demo twice returns the same counts."""
|
||||||
|
|
@ -298,6 +306,12 @@ class TestSeedDemo:
|
||||||
assert resp2.json()["postings"] == resp1.json()["postings"]
|
assert resp2.json()["postings"] == resp1.json()["postings"]
|
||||||
assert resp2.json()["applications"] == resp1.json()["applications"]
|
assert resp2.json()["applications"] == resp1.json()["applications"]
|
||||||
assert resp2.json()["sections"] == resp1.json()["sections"]
|
assert resp2.json()["sections"] == resp1.json()["sections"]
|
||||||
|
assert resp2.json()["clusters"] == resp1.json()["clusters"]
|
||||||
|
assert resp2.json()["deadlines"] == resp1.json()["deadlines"]
|
||||||
|
assert resp2.json()["suggestions"] == resp1.json()["suggestions"]
|
||||||
|
assert resp2.json()["notifications"] == resp1.json()["notifications"]
|
||||||
|
assert resp2.json()["task_runs"] == resp1.json()["task_runs"]
|
||||||
|
assert resp2.json()["cv_artifacts"] == resp1.json()["cv_artifacts"]
|
||||||
|
|
||||||
def test_seed_demo_has_nudge_candidate(self, client):
|
def test_seed_demo_has_nudge_candidate(self, client):
|
||||||
"""After seeding, /today should show a nudge for the backdated sent app."""
|
"""After seeding, /today should show a nudge for the backdated sent app."""
|
||||||
|
|
@ -313,6 +327,104 @@ class TestSeedDemo:
|
||||||
digest = resp.json()["digest"]
|
digest = resp.json()["digest"]
|
||||||
assert len(digest) >= 1
|
assert len(digest) >= 1
|
||||||
|
|
||||||
|
# --- WS1: Extended seed demo tests (8 new) ---
|
||||||
|
|
||||||
|
def test_seed_demo_agency_cluster_present(self, client):
|
||||||
|
"""Seed creates a 3-posting agency cluster with the same cluster_id."""
|
||||||
|
client.post("/api/concierge/seed-demo")
|
||||||
|
postings = client.get("/api/postings").json()
|
||||||
|
agency_names = {"Aderanto AB", "Wise IT", "TechTalent Nord"}
|
||||||
|
agency_postings = [p for p in postings if p.get("company") in agency_names]
|
||||||
|
assert len(agency_postings) == 3
|
||||||
|
cluster_ids = {p["cluster_id"] for p in agency_postings if p.get("cluster_id")}
|
||||||
|
assert len(cluster_ids) == 1, f"Expected 1 cluster_id, got {cluster_ids}"
|
||||||
|
|
||||||
|
def test_seed_demo_deadlines_populated(self, client):
|
||||||
|
"""Seed creates at least 2 postings with apply_by in the next 7 days."""
|
||||||
|
client.post("/api/concierge/seed-demo")
|
||||||
|
resp = client.get("/api/today")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
deadlines = resp.json().get("deadlines", [])
|
||||||
|
assert len(deadlines) >= 2
|
||||||
|
for d in deadlines:
|
||||||
|
assert d["apply_by"] is not None
|
||||||
|
|
||||||
|
def test_seed_demo_red_flag_rationale(self, client):
|
||||||
|
"""Seed creates an application with red_flags in its score_rationale."""
|
||||||
|
client.post("/api/concierge/seed-demo")
|
||||||
|
apps = client.get("/api/applications").json()
|
||||||
|
red_flag_apps = [
|
||||||
|
a for a in apps
|
||||||
|
if a.get("score_rationale") and isinstance(a["score_rationale"], dict)
|
||||||
|
and "red_flags" in a["score_rationale"]
|
||||||
|
]
|
||||||
|
assert len(red_flag_apps) >= 1
|
||||||
|
red_flags = red_flag_apps[0]["score_rationale"]["red_flags"]
|
||||||
|
assert isinstance(red_flags, list)
|
||||||
|
assert any("unpaid trial" in str(rf).lower() for rf in red_flags)
|
||||||
|
|
||||||
|
def test_seed_demo_has_interviewing_application(self, client):
|
||||||
|
"""Seed creates at least one application in interviewing state."""
|
||||||
|
client.post("/api/concierge/seed-demo")
|
||||||
|
apps = client.get("/api/applications").json()
|
||||||
|
interviewing = [a for a in apps if a["state"] == "interviewing"]
|
||||||
|
assert len(interviewing) >= 1
|
||||||
|
|
||||||
|
def test_seed_demo_has_cover_letter_artifact(self, client):
|
||||||
|
"""Seed creates a cover_letter artifact (origin user_drafted) with Swedish text on the approved app."""
|
||||||
|
client.post("/api/concierge/seed-demo")
|
||||||
|
apps = client.get("/api/applications").json()
|
||||||
|
for a in apps:
|
||||||
|
artifacts = client.get(f"/api/applications/{a['id']}/artifacts").json()
|
||||||
|
for art in artifacts:
|
||||||
|
if art["kind"] == "cover_letter" and art["origin"] == "user_drafted":
|
||||||
|
return
|
||||||
|
assert False, "No user_drafted cover_letter artifact found"
|
||||||
|
|
||||||
|
def test_seed_demo_suggestions_present(self, client):
|
||||||
|
"""Seed creates 2 pending email_suggestion rows with expected classifications."""
|
||||||
|
client.post("/api/concierge/seed-demo")
|
||||||
|
suggestions = client.get("/api/suggestions").json()
|
||||||
|
assert len(suggestions) == 2
|
||||||
|
classifications = {s["classification"] for s in suggestions}
|
||||||
|
assert "interview_invite" in classifications
|
||||||
|
assert "question" in classifications
|
||||||
|
# Verify the interview_invite comes from recruiter@festina-demo.se
|
||||||
|
interview_suggestion = [s for s in suggestions if s["classification"] == "interview_invite"][0]
|
||||||
|
assert interview_suggestion["mailbox_from"] == "recruiter@festina-demo.se"
|
||||||
|
|
||||||
|
def test_seed_demo_notification_log_present(self, client):
|
||||||
|
"""Seed creates 3 notification_log rows: 2 delivered, 1 webhook failed."""
|
||||||
|
client.post("/api/concierge/seed-demo")
|
||||||
|
resp = client.get("/api/notifications/log")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
logs = resp.json()
|
||||||
|
assert len(logs) == 3
|
||||||
|
# At least one delivered (daily_digest or email_suggestion)
|
||||||
|
delivered = [l for l in logs if l["delivered"] is True]
|
||||||
|
assert len(delivered) >= 2
|
||||||
|
# At least one webhook failed with error text
|
||||||
|
failed = [l for l in logs if l["delivered"] is False]
|
||||||
|
assert len(failed) >= 1
|
||||||
|
assert failed[0]["error"] is not None
|
||||||
|
assert len(failed[0]["error"]) > 0
|
||||||
|
|
||||||
|
def test_seed_demo_task_run_telemetry_variance(self, client):
|
||||||
|
"""Seed creates 6 task_run rows across multiple providers and models."""
|
||||||
|
client.post("/api/concierge/seed-demo")
|
||||||
|
resp = client.get("/api/telemetry/tasks")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
tasks = resp.json()
|
||||||
|
assert len(tasks) == 6
|
||||||
|
providers = {t["provider"] for t in tasks}
|
||||||
|
models = {t["model"] for t in tasks}
|
||||||
|
assert len(providers) >= 3, f"Expected >= 3 providers, got {providers}"
|
||||||
|
assert len(models) >= 4, f"Expected >= 4 models, got {models}"
|
||||||
|
# Verify cost variance for CostDisplay
|
||||||
|
costs = [t["cost_usd"] for t in tasks if t["cost_usd"] is not None]
|
||||||
|
assert len(costs) >= 2
|
||||||
|
assert max(costs) > min(costs)
|
||||||
|
|
||||||
|
|
||||||
# --- SMTP Transport ---
|
# --- SMTP Transport ---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue