You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
5.6 KiB
Python

"""Tests for the proactive lead ledger status transitions."""
from datetime import date
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool
from gimme_job.db.proactive_repo import ProactiveLeadRepo
from gimme_job.models.db import Base
from gimme_job.models.dto import ProactiveLeadCandidate
@pytest.fixture()
def session():
engine = create_engine(
"sqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool
)
Base.metadata.create_all(engine)
factory = sessionmaker(bind=engine)
s = factory()
yield s
s.close()
def _cand(status: str, url: str, title: str = "Orthodontist") -> ProactiveLeadCandidate:
return ProactiveLeadCandidate(
status=status,
title=title,
official_url=url,
source_engine="duckduckgo",
source_query="orthodontist FQHC Alabama",
fingerprint=f"fp-{url}",
)
def test_new_active_lead(session):
repo = ProactiveLeadRepo()
changed, status = repo.upsert(
session, _cand("ACTIVE", "https://a.org/1"), date(2026, 9, 8)
)
assert changed is True
assert status == "NEW"
lead = ProactiveLeadRepo().get_by_fingerprint(session, "fp-https://a.org/1")
assert lead.is_active is True
assert lead.ever_active is True
assert lead.is_new is True
def test_active_twice_is_still_open(session):
repo = ProactiveLeadRepo()
repo.upsert(session, _cand("ACTIVE", "https://a.org/1"), date(2026, 9, 8))
changed, status = repo.upsert(session, _cand("ACTIVE", "https://a.org/1"), date(2026, 9, 9))
assert changed is True
assert status == "STILL_OPEN"
lead = repo.get_by_fingerprint(session, "fp-https://a.org/1")
assert lead.is_new is False
assert lead.is_active is True
def test_closed_then_active_is_reopened(session):
repo = ProactiveLeadRepo()
repo.upsert(session, _cand("ACTIVE", "https://a.org/1"), date(2026, 9, 8))
repo.upsert(session, _cand("CLOSED", "https://a.org/1"), date(2026, 9, 10))
lead = repo.get_by_fingerprint(session, "fp-https://a.org/1")
assert lead.status == "CLOSED"
assert lead.is_active is False
changed, status = repo.upsert(session, _cand("ACTIVE", "https://a.org/1"), date(2026, 9, 12))
assert status == "REOPENED"
assert changed is True
lead = repo.get_by_fingerprint(session, "fp-https://a.org/1")
assert lead.is_new is True
assert lead.is_active is True
def test_verify_lead_stored_as_verify(session):
repo = ProactiveLeadRepo()
changed, status = repo.upsert(
session, _cand("VERIFY", "https://indeed.com/jobs/1"), date(2026, 9, 8)
)
assert changed is True
assert status == "VERIFY"
lead = repo.get_by_fingerprint(session, "fp-https://indeed.com/jobs/1")
assert lead.is_active is False
assert lead.ever_active is False
def test_verify_upgrade_to_active_is_new(session):
repo = ProactiveLeadRepo()
repo.upsert(session, _cand("VERIFY", "https://indeed.com/jobs/1"), date(2026, 9, 8))
changed, status = repo.upsert(
session, _cand("ACTIVE", "https://indeed.com/jobs/1"), date(2026, 9, 9)
)
assert status == "NEW"
lead = repo.get_by_fingerprint(session, "fp-https://indeed.com/jobs/1")
assert lead.ever_active is True
assert lead.is_active is True
def test_closed_first_seen_not_stored(session):
changed, status = ProactiveLeadRepo().upsert(
session, _cand("CLOSED", "https://x.org/9"), date(2026, 9, 8)
)
assert changed is False
assert status == "CLOSED"
assert ProactiveLeadRepo().get_by_fingerprint(session, "fp-https://x.org/9") is None
def test_stale_transition_from_active(session):
repo = ProactiveLeadRepo()
repo.upsert(session, _cand("ACTIVE", "https://a.org/2"), date(2026, 9, 8))
changed, status = repo.upsert(session, _cand("STALE", "https://a.org/2"), date(2026, 9, 9))
assert status == "STALE"
lead = repo.get_by_fingerprint(session, "fp-https://a.org/2")
assert lead.is_active is False
def test_fields_refreshed_on_upsert(session):
repo = ProactiveLeadRepo()
repo.upsert(session, _cand("ACTIVE", "https://a.org/3", title="Orthodontist"), date(2026, 9, 8))
cand = _cand("ACTIVE", "https://a.org/3", title="Staff Orthodontist")
cand.salary_text = "$200k-$250k"
cand.evidence = {"apply_found": True}
repo.upsert(session, cand, date(2026, 9, 9))
lead = repo.get_by_fingerprint(session, "fp-https://a.org/3")
assert lead.title == "Staff Orthodontist"
assert lead.salary_text == "$200k-$250k"
assert lead.evidence is not None
def test_get_inactive_returns_closed_and_stale(session):
repo = ProactiveLeadRepo()
repo.upsert(session, _cand("ACTIVE", "https://a.org/10"), date(2026, 9, 8))
repo.upsert(session, _cand("ACTIVE", "https://a.org/11"), date(2026, 9, 8))
repo.upsert(session, _cand("ACTIVE", "https://a.org/12"), date(2026, 9, 8))
# close two of them
repo.upsert(session, _cand("CLOSED", "https://a.org/10"), date(2026, 9, 9))
repo.upsert(session, _cand("STALE", "https://a.org/11"), date(2026, 9, 9))
inactive = repo.get_inactive(session)
urls = {rec.official_url for rec in inactive}
assert "https://a.org/10" in urls
assert "https://a.org/11" in urls
assert "https://a.org/12" not in urls
def test_get_inactive_respects_limit(session):
repo = ProactiveLeadRepo()
for i in range(5):
repo.upsert(session, _cand("ACTIVE", f"https://a.org/l{i}"), date(2026, 9, 8))
repo.upsert(session, _cand("CLOSED", f"https://a.org/l{i}"), date(2026, 9, 9))
assert len(repo.get_inactive(session, limit=2)) == 2