"""Public aggregates, live feed, search, rankings, industries/countries, signals, sitemap — shapes, caching and graceful degradation.""" from __future__ import annotations import pytest import test_api_support as support client = support.client fixture_data = support.fixture_data pytestmark = pytest.mark.asyncio(loop_scope="session") V = "/api/v1" async def test_health(client): # type: ignore[no-untyped-def] r = await client.get("/health") assert r.status_code == 200 and r.json()["db"] is True assert (await client.get(f"{V}/health")).status_code == 200 async def test_stats_shape_and_cache_headers(client): # type: ignore[no-untyped-def] r = await client.get(f"{V}/stats") assert r.status_code == 200 body = r.json() for key in ("companies", "companies_active", "sensors", "sensors_active", "observations", "snapshots", "changes", "meaningful_changes", "events", "jobs_open", "countries", "industries", "observations_today", "changes_today", "events_today", "dataset_started_at", "dataset_age_days", "oldest_history_days", "last_observation_at", "archive"): assert key in body, key assert body["companies"] >= 2 and body["events"] >= 4 assert set(body["archive"]) == {"objects", "bytes"} assert r.headers["cache-control"].startswith("public, max-age=60") assert r.headers["etag"].startswith('W/"') r2 = await client.get(f"{V}/stats", headers={"If-None-Match": r.headers["etag"]}) assert r2.status_code == 304 async def test_stats_history_and_index(client): # type: ignore[no-untyped-def] r = await client.get(f"{V}/stats/history?days=30") assert r.status_code == 200 and isinstance(r.json()["items"], list) r = await client.get(f"{V}/index") body = r.json() assert r.status_code == 200 for key in ("value", "baseline", "delta_7d", "delta_30d", "series", "by_type", "by_country", "by_industry", "formula_version"): assert key in body assert body["baseline"] == 100 async def test_system(client): # type: ignore[no-untyped-def] r = await client.get(f"{V}/system") assert r.status_code == 200 body = r.json() for key in ("sensors_online", "sensors_failing", "observations_today", "events_today", "countries_covered", "queue_lag_s", "scheduler_last_tick_at", "fetch_per_min", "success_rate_24h"): assert key in body assert body["sensors_online"] >= 3 async def test_pulse_full_shape(client, fixture_data): # type: ignore[no-untyped-def] r = await client.get(f"{V}/pulse") assert r.status_code == 200 body = r.json() for key in ("stats", "live", "movers", "hiring", "launches", "pricing", "ai", "industries", "countries", "trending", "activity_index", "map"): assert key in body, key assert any(e["id"] == fixture_data["ev_pricing"] for e in body["pricing"]) assert any(c["slug"] == fixture_data["alpha_slug"] for c in body["movers"]) mover = next(c for c in body["movers"] if c["slug"] == fixture_data["alpha_slug"]) assert mover["rank"] >= 1 and mover["value"] == 72.3 and "sparkline" in mover assert set(body["activity_index"]) == {"value", "delta_7d", "series"} assert any(b["country"] == "ZZ" for b in body["map"]) async def test_methodology(client): # type: ignore[no-untyped-def] body = (await client.get(f"{V}/methodology")).json() assert {m["metric"] for m in body["metrics"]} >= {"activity_score", "hiring_momentum_30d", "ai_adoption", "corporate_change_index"} assert "PRICING" in body["event_types"] and "significance_bands" in body and body["confidence_labels"][0]["label"] == "VERIFIED" async def test_live_and_since(client, fixture_data): # type: ignore[no-untyped-def] r = await client.get(f"{V}/live?limit=10&country=ZZ") assert r.status_code == 200 and r.headers["cache-control"] == "no-store" body = r.json() ids = [e["id"] for e in body["items"]] assert fixture_data["ev_pricing"] in ids and fixture_data["ev_retracted"] not in ids ev = body["items"][0] for key in ("id", "company", "event_type", "event_subtype", "importance", "confidence", "confidence_label", "title", "payload", "entities", "tags", "detected_at", "source_url", "origin", "status"): assert key in ev assert set(ev["company"]) == {"id", "slug", "display_name", "canonical_domain", "country", "logo_url"} assert ev["detected_at"].endswith("Z") r = await client.get(f"{V}/live", params={"since": body["cursor"], "country": "ZZ"}) assert r.status_code == 200 and r.json()["items"] == [] r = await client.get(f"{V}/live", params={"event_type": "PRICING", "min_importance": 0.7, "country": "ZZ"}) assert all(e["event_type"] == "PRICING" for e in r.json()["items"]) and r.json()["items"] assert (await client.get(f"{V}/live?since=not-a-date")).status_code == 422 async def test_live_stream_first_bytes(client): # type: ignore[no-untyped-def] r = await client.get(f"{V}/live/stream?max_s=1") assert r.status_code == 200 assert r.headers["content-type"].startswith("text/event-stream") assert r.headers.get("x-accel-buffering") == "no" and r.headers["cache-control"] == "no-store, no-transform" assert "event: heartbeat" in r.text and '"cursor"' in r.text and "event: end" in r.text async def test_rankings(client, fixture_data): # type: ignore[no-untyped-def] r = await client.get(f"{V}/rankings?kind=most_active&window=7d&country=ZZ") assert r.status_code == 200 and r.headers["cache-control"].startswith("public, max-age=120") body = r.json() assert body["kind"] == "most_active" and body["window"] == "7d" slugs = [i["slug"] for i in body["items"]] assert slugs[:2] == [fixture_data["alpha_slug"], fixture_data["beta_slug"]] top = body["items"][0] assert top["rank"] == 1 and top["value"] == 72.3 and "delta" in top r = await client.get(f"{V}/rankings?kind=hiring_decline&window=30d&country=ZZ") assert [i["slug"] for i in r.json()["items"]] == [fixture_data["beta_slug"]] r = await client.get(f"{V}/rankings?kind=pricing_changes&window=7d") assert any(i["slug"] == fixture_data["alpha_slug"] and i["value"] == 1 for i in r.json()["items"]) assert (await client.get(f"{V}/rankings?kind=bogus")).status_code == 422 async def test_industries(client, fixture_data): # type: ignore[no-untyped-def] r = await client.get(f"{V}/industries") assert r.status_code == 200 row = next(i for i in r.json()["items"] if i["slug"] == fixture_data["industry"]) for key in ("slug", "name", "parent_slug", "companies", "events_7d", "events_30d", "hiring_momentum_30d", "activity_score", "ai_adoption", "top_event_types"): assert key in row assert row["companies"] == 2 and row["events_30d"] == 4 and row["activity_score"] == 51.2 and "PRICING" in row["top_event_types"] r = await client.get(f"{V}/industries/{fixture_data['industry']}") body = r.json() assert r.status_code == 200 for key in ("description", "companies", "events", "hiring", "series", "countries", "trending"): assert key in body assert body["hiring"]["open"] == 2 and body["countries"][0] == {"country": "ZZ", "companies": 2} assert len(body["series"]) == 10 and body["companies"][0]["slug"] == fixture_data["alpha_slug"] assert (await client.get(f"{V}/industries/does-not-exist")).status_code == 404 async def test_countries(client, fixture_data): # type: ignore[no-untyped-def] r = await client.get(f"{V}/countries") row = next(c for c in r.json()["items"] if c["code"] == "ZZ") for key in ("code", "name", "region", "companies", "events_7d", "events_30d", "hiring_momentum_30d", "activity_score", "industry_mix", "lat", "lon"): assert key in row assert row["companies"] == 2 and row["industry_mix"][0]["industry"] == fixture_data["industry"] and row["slug"] == "ztestland" for key in ("ZZ", "zz", "ztestland"): r = await client.get(f"{V}/countries/{key}") assert r.status_code == 200, key body = r.json() for key in ("companies", "events", "movers", "new_entrants", "series", "industries"): assert key in body assert body["movers"][0]["slug"] == fixture_data["alpha_slug"] and len(body["new_entrants"]) == 2 assert (await client.get(f"{V}/countries/atlantis")).status_code == 404 async def test_signals_trends_map(client, fixture_data): # type: ignore[no-untyped-def] r = await client.get(f"{V}/signals?scope=company&company={fixture_data['alpha_slug']}") items = r.json()["items"] assert r.status_code == 200 and items[0]["kind"] == "hiring_surge" and items[0]["company"]["slug"] == fixture_data["alpha_slug"] r = await client.get(f"{V}/trends?window=30d") assert r.status_code == 200 and isinstance(r.json()["items"], list) r = await client.get(f"{V}/map?metric=companies") assert r.status_code == 200 buckets = r.json()["buckets"] zz = [b for b in buckets if b["country"] == "ZZ"] assert zz and {"lat", "lon", "country", "city", "companies", "events_30d", "jobs_open", "top"} <= set(zz[0]) assert any(b["city"] == "Testville" and b["jobs_open"] == 2 for b in zz) async def test_search_suggest_ask(client, fixture_data): # type: ignore[no-untyped-def] r = await client.get(f"{V}/search", params={"q": f"ztest alpha {fixture_data['suffix']}"}) body = r.json() assert r.status_code == 200 and body["companies"][0]["slug"] == fixture_data["alpha_slug"] and "took_ms" in body assert any(e["id"] == fixture_data["ev_pricing"] for e in (await client.get(f"{V}/search", params={"q": "starter price increased", "types": "events"})).json()["events"]) people = (await client.get(f"{V}/search", params={"q": "jane ztest", "types": "people"})).json()["people"] assert people and people[0]["company"]["slug"] == fixture_data["alpha_slug"] r = await client.get(f"{V}/search", params={"q": f"alphaz {fixture_data['suffix']}"}) # alias assert r.json()["companies"][0]["slug"] == fixture_data["alpha_slug"] assert (await client.get(f"{V}/search", params={"q": "zt"})).status_code == 200 r = await client.get(f"{V}/search/suggest", params={"q": "ztest al"}) items = r.json()["items"] assert r.status_code == 200 and len(items) <= 10 and items[0]["kind"] == "company" and items[0]["href"].startswith("/company/") assert any(i["kind"] == "event_type" for i in (await client.get(f"{V}/search/suggest", params={"q": "pric"})).json()["items"]) r = await client.get(f"{V}/ask", params={"q": "pricing changes in Ztestland this week"}) body = r.json() assert r.status_code == 200 for key in ("interpretation", "answer", "companies", "events", "sources"): assert key in body assert any(e["id"] == fixture_data["ev_pricing"] for e in body["events"]) and body["sources"] assert "fired" not in body["answer"].lower() async def test_sitemap(client, fixture_data): # type: ignore[no-untyped-def] r = await client.get(f"{V}/sitemap?kind=companies") body = r.json() assert r.status_code == 200 and body["pages"] >= 1 slugs = {i["slug"] for i in body["items"]} assert fixture_data["alpha_slug"] in slugs # indexed = true assert fixture_data["beta_slug"] not in slugs # 1 sensor < seo_min_sensors assert fixture_data["industry"] in {i["slug"] for i in (await client.get(f"{V}/sitemap?kind=industries")).json()["items"]} assert "ztestland" in {i["slug"] for i in (await client.get(f"{V}/sitemap?kind=countries")).json()["items"]}