"""ILOSTAT connector — offline tests on a trimmed DF_UNE_2EAP_SEX_AGE_RT CSV (CAN, FRA, SOM, X01), plus live smoke.""" from __future__ import annotations from datetime import date import pytest from countryatlas.connectors.ilo import ILOConnector from countryatlas.models import IndicatorSourceSpec from tests.connectors._helpers import install_fake_get, raw_from_file @pytest.fixture def fake_get(monkeypatch): return install_fake_get(monkeypatch) SPEC =IndicatorSourceSpec(indicator_id="unemployment-rate", connector="ilo", dataset="DF_UNE_2EAP_SEX_AGE_RT", code=".A..SEX_T.AGE_YTHADULT_YGE15", frequency="A", priority=4) def _raw(fixtures_dir, **meta): return raw_from_file("ilo", SPEC.dataset, SPEC.code, fixtures_dir / "ilo" / "DF_UNE_2EAP_SEX_AGE_RT.csv", "text/csv", **meta) def test_normalize_drops_aggregates_flags_projections_and_imputations(fixtures_dir): conn = ILOConnector() rows = conn.normalize(_raw(fixtures_dir, dataflow_meta={"release_year": 2025, "name": "… Nov. 2025"}), SPEC) assert {r.country_id for r in rows} == {"CAN", "FRA", "SOM"} # X01 aggregate dropped can = {r.year: r for r in rows if r.country_id == "CAN"} assert can[2024].is_estimate is False and can[2024].is_forecast is False # OBS_STATUS = R assert can[2025].is_estimate is True and can[2025].is_forecast is False # nowcast (blank status), release year assert can[2026].is_forecast is True and can[2027].is_forecast is True assert can[2025].value == pytest.approx(6.907) # = WB SL.UEM.TOTL.ZS 2025 som = {r.year: r for r in rows if r.country_id == "SOM"} assert som[2024].is_estimate is True and som[2024].metadata["low"] == pytest.approx(4.737) assert all(r.frequency == "A" and r.period == date(r.year, 1, 1) and r.unit == "% of labour force" for r in rows) assert conn.validate(rows).quarantine_dataset is False def test_release_year_fallback_is_current_year(fixtures_dir): from datetime import UTC, datetime rows = ILOConnector().normalize(_raw(fixtures_dir), SPEC) # no dataflow_meta → years > now.year are forecasts y = datetime.now(UTC).year assert all(r.is_forecast == (r.year > y) for r in rows) def test_fetch_builds_verified_url_and_parses_release_year(fixtures_dir, fake_get): conn = ILOConnector() csv_body = (fixtures_dir / "ilo" / "DF_UNE_2EAP_SEX_AGE_RT.csv").read_bytes() flow = (fixtures_dir / "ilo" / "dataflow.json").read_bytes() def router(url, params): if "/dataflow/ILO/" in url: return flow, "application/vnd.sdmx.structure+json" return csv_body, "text/csv" calls = fake_get(conn, router) p = conn.fetch(SPEC) assert calls[0]["url"] == "https://sdmx.ilo.org/rest/dataflow/ILO/DF_UNE_2EAP_SEX_AGE_RT" assert calls[1]["url"] == "https://sdmx.ilo.org/rest/data/ILO,DF_UNE_2EAP_SEX_AGE_RT/.A..SEX_T.AGE_YTHADULT_YGE15" assert calls[1]["params"] == {"format": "csv"} assert p.meta["dataflow_meta"]["release_year"] == 2025 assert "Nov. 2025" in p.meta["dataflow_meta"]["name"] rows = conn.normalize(p, SPEC) assert {r.year for r in rows if r.is_forecast} == {2026, 2027} @pytest.mark.live def test_live_youth_unemployment(): conn = ILOConnector() spec = SPEC.model_copy(update={"indicator_id": "youth-unemployment-rate", "code": ".A..SEX_T.AGE_YTHADULT_Y15-24", "params": {"startPeriod": "2023"}}) rows = conn.normalize(conn.fetch(spec), spec) assert len({r.country_id for r in rows}) >= 150 and "CAN" in {r.country_id for r in rows} assert conn.validate(rows).quarantine_dataset is False