test_auth_probe.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. """auth-probe 路由测试:入站实体授权探测与过滤(进程内,无网络)。"""
  2. from __future__ import annotations
  3. import time
  4. import pytest
  5. fastapi_testclient = pytest.importorskip("fastapi.testclient")
  6. TestClient = fastapi_testclient.TestClient
  7. import app as sim_app # noqa: E402
  8. from catalog import sample_adapters as sa # noqa: E402
  9. _CATALOG = {"objects": [
  10. {"objectCode": "ITEM", "apiInbound": {"supported": True,
  11. "entityCode": "MDM_ITEM",
  12. "contractVersion": "v1"}},
  13. {"objectCode": "CUSTOMER", "apiInbound": {"supported": True,
  14. "entityCode": "MDM_CUSTOMER",
  15. "contractVersion": "v1"}},
  16. {"objectCode": "NO_INBOUND", "apiInbound": {"supported": False,
  17. "entityCode": "MDM_X"}},
  18. ]}
  19. class _FakeClient:
  20. def op_schema(self, entity, contract_version=None):
  21. return (403 if entity == "MDM_CUSTOMER" else 200), {"message": "ok"}, {}
  22. def _reset_cache(monkeypatch):
  23. monkeypatch.setitem(sim_app._AUTH_PROBE_CACHE, "at", 0.0)
  24. monkeypatch.setitem(sim_app._AUTH_PROBE_CACHE, "data", None)
  25. def _patch_reachable(monkeypatch):
  26. monkeypatch.setattr(sim_app.aidop_probe, "check_reachable",
  27. lambda *a, **k: {"reachable": True})
  28. def test_auth_probe_filters_unauthorized(monkeypatch):
  29. monkeypatch.setattr(sim_app, "_build_inbound_client", lambda: _FakeClient())
  30. monkeypatch.setattr(sa, "load_catalog", lambda: _CATALOG)
  31. _patch_reachable(monkeypatch)
  32. _reset_cache(monkeypatch)
  33. r = TestClient(sim_app.app).get("/api/inbound/auth-probe", params={"refresh": 1})
  34. assert r.status_code == 200
  35. body = r.json()
  36. assert body["cached"] is False
  37. assert body["entities"] == {"MDM_ITEM": True, "MDM_CUSTOMER": False}
  38. def test_auth_probe_unreachable_marks_all_false_without_probing(monkeypatch):
  39. monkeypatch.setattr(sim_app, "_build_inbound_client",
  40. lambda: (_ for _ in ()).throw(AssertionError("should not call")))
  41. monkeypatch.setattr(sa, "load_catalog", lambda: _CATALOG)
  42. monkeypatch.setattr(sim_app.aidop_probe, "check_reachable",
  43. lambda *a, **k: {"reachable": False, "error": "down"})
  44. _reset_cache(monkeypatch)
  45. r = TestClient(sim_app.app).get("/api/inbound/auth-probe", params={"refresh": 1})
  46. assert r.status_code == 200
  47. body = r.json()
  48. assert body["entities"] == {"MDM_ITEM": False, "MDM_CUSTOMER": False}
  49. assert any("不可达" in e for e in body["probeErrors"])
  50. def test_auth_probe_missing_credentials_400(monkeypatch):
  51. monkeypatch.setattr(sim_app, "_env", lambda name: "")
  52. _reset_cache(monkeypatch)
  53. r = TestClient(sim_app.app).get("/api/inbound/auth-probe", params={"refresh": 1})
  54. assert r.status_code == 400
  55. assert "AIDOP_SIM_INBOUND_ACCESS_KEY" in r.json()["detail"]
  56. def test_auth_probe_serves_cache_without_client(monkeypatch):
  57. monkeypatch.setitem(sim_app._AUTH_PROBE_CACHE, "at", time.monotonic())
  58. monkeypatch.setitem(sim_app._AUTH_PROBE_CACHE, "data",
  59. {"entities": {"MDM_ITEM": True}, "probedAt": "x", "probeErrors": []})
  60. monkeypatch.setattr(sim_app, "_build_inbound_client",
  61. lambda: (_ for _ in ()).throw(AssertionError("should not call")))
  62. r = TestClient(sim_app.app).get("/api/inbound/auth-probe")
  63. assert r.status_code == 200
  64. assert r.json()["cached"] is True