from pathlib import Path import pytest from fin_hub.ingest.anthropic import parse_anthropic_billing_csv from fin_hub.ingest.cloud import parse_cloud_cost_csv from fin_hub.ingest.hosteurope import parse_hosteurope_csv FIXTURES = Path(__file__).parent / "fixtures" def test_parse_cloud_cost_csv(): rows = parse_cloud_cost_csv(FIXTURES / "cloud-costs.csv") assert len(rows) == 3 assert rows[0].service == "state-hub" assert rows[0].amount == 42.5 def test_parse_anthropic_billing_csv(): rows = parse_anthropic_billing_csv(FIXTURES / "anthropic-billing.csv") assert len(rows) == 2 assert rows[0].provider == "anthropic" assert rows[0].tokens_in == 12000 def test_parse_hosteurope_csv(): rows = parse_hosteurope_csv(FIXTURES / "hosteurope.csv") assert len(rows) == 2 assert rows[0].service_id == "dedicated-server-m" assert rows[0].period_month == "2026-06" def test_parse_hosteurope_client_attribution(tmp_path: Path): source = tmp_path / "attributed.csv" source.write_text( "product,amount,currency,invoice_date,client_id,application_id,app_instance_id\n" "Managed cluster,42.00,EUR,2026-07-01,acme,portal,prod-01\n", encoding="utf-8", ) row = parse_hosteurope_csv(source)[0] assert row.client_id == "acme" assert row.application_id == "portal" assert row.app_instance_id == "prod-01" assert row.cost_attribution_key == "client:acme|app:portal|instance:prod-01" def test_parse_hosteurope_rejects_partial_attribution(tmp_path: Path): source = tmp_path / "partial.csv" source.write_text( "product,amount,currency,invoice_date,client_id\n" "Managed cluster,42.00,EUR,2026-07-01,acme\n", encoding="utf-8", ) with pytest.raises(ValueError, match="must be supplied together"): parse_hosteurope_csv(source)