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
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 |