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.
129 lines
3.8 KiB
Python
129 lines
3.8 KiB
Python
"""Integration test: filing pipeline (poll → fetch → parse → event in DB)."""
|
|
|
|
import datetime as dt
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
FIXTURES = Path(__file__).parent.parent / "fixtures"
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.asyncio
|
|
async def test_document_upsert_idempotency_via_helpers(db_session):
|
|
"""Upsert helper inserts same document twice → only one row."""
|
|
import datetime as dt
|
|
|
|
from sqlalchemy import func, select
|
|
|
|
from libs.db.helpers import upsert
|
|
from libs.db.models import Document
|
|
|
|
values = {
|
|
"document_id": "DOC::idempotency::test::2026-01-01::IDEMACC001",
|
|
"source_name": "sec",
|
|
"form_type": "8-K",
|
|
"filing_date": dt.date(2026, 1, 1),
|
|
"accession_no": "IDEMACC001",
|
|
"parsed_status": "pending",
|
|
"created_at_utc": dt.datetime.now(tz=dt.UTC),
|
|
"updated_at_utc": dt.datetime.now(tz=dt.UTC),
|
|
}
|
|
|
|
await upsert(db_session, Document, values, index_elements=["document_id"])
|
|
await upsert(db_session, Document, values, index_elements=["document_id"])
|
|
await db_session.flush()
|
|
|
|
result = await db_session.execute(
|
|
select(func.count()).where(
|
|
Document.document_id == "DOC::idempotency::test::2026-01-01::IDEMACC001"
|
|
)
|
|
)
|
|
count = result.scalar_one()
|
|
assert count == 1
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.asyncio
|
|
async def test_document_upsert_idempotency(db_session):
|
|
"""Inserting same document twice should not create duplicates."""
|
|
from sqlalchemy import select
|
|
|
|
from libs.db.models import Document
|
|
|
|
doc_id = "DOC::test::ISSUER::X::2026-01-01::ACC001"
|
|
doc1 = Document(
|
|
document_id=doc_id,
|
|
source_name="sec",
|
|
form_type="8-K",
|
|
filing_date=dt.date(2026, 1, 29),
|
|
accession_no="ACC001",
|
|
parsed_status="pending",
|
|
)
|
|
db_session.add(doc1)
|
|
await db_session.flush()
|
|
|
|
# Try to insert again (should conflict on unique accession+form_type)
|
|
result = await db_session.execute(select(Document).where(Document.document_id == doc_id))
|
|
rows = result.scalars().all()
|
|
assert len(rows) == 1
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.asyncio
|
|
async def test_event_parse_lifecycle(db_session):
|
|
"""Create issuer → document → event → event_parse chain."""
|
|
from libs.db.models import Document, Event, EventParse, IssuerMaster
|
|
|
|
# Create issuer — use TEST prefix to avoid conflicts with real pipeline data
|
|
issuer = IssuerMaster(
|
|
issuer_id="ISSUER::TEST::0000320193",
|
|
issuer_name="Apple Inc.",
|
|
ticker="AAPL_TEST",
|
|
)
|
|
db_session.add(issuer)
|
|
await db_session.flush()
|
|
|
|
# Create document
|
|
doc = Document(
|
|
document_id="DOC::test::ISSUER::TEST::2026-01-29::ACC001",
|
|
source_name="sec",
|
|
issuer_id="ISSUER::TEST::0000320193",
|
|
form_type="8-K",
|
|
filing_date=dt.date(2026, 1, 29),
|
|
accession_no="ACC001",
|
|
parsed_status="ready_for_parse",
|
|
)
|
|
db_session.add(doc)
|
|
await db_session.flush()
|
|
|
|
# Create event
|
|
event = Event(
|
|
event_id="EVT::test::ISSUER::TEST::2026-01-29::ACC001::earnings_release::0",
|
|
primary_document_id=doc.document_id,
|
|
issuer_id="ISSUER::TEST::0000320193",
|
|
event_type="earnings_release",
|
|
event_direction="bullish",
|
|
event_date=dt.date(2026, 1, 29),
|
|
parser_version="rule-1.0.0",
|
|
parse_confidence=0.78,
|
|
status="pending",
|
|
)
|
|
db_session.add(event)
|
|
await db_session.flush()
|
|
|
|
# Create event parse
|
|
parse = EventParse(
|
|
event_id=event.event_id,
|
|
parser_kind="rule",
|
|
parser_version="rule-1.0.0",
|
|
schema_version="1.0.0",
|
|
output_json={"event_type": "earnings_release"},
|
|
validation_status="valid",
|
|
)
|
|
db_session.add(parse)
|
|
await db_session.flush()
|
|
|
|
assert parse.event_parse_id is not None
|
|
assert event.status == "pending"
|