test_lightrag_client.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. from __future__ import annotations
  2. import pytest
  3. class Response:
  4. def __init__(self, payload, status_code=200):
  5. self.payload = payload
  6. self.status_code = status_code
  7. def raise_for_status(self):
  8. if self.status_code >= 400:
  9. raise RuntimeError(f"HTTP {self.status_code}")
  10. def json(self):
  11. return self.payload
  12. class Transport:
  13. def __init__(self, responses):
  14. self.responses = list(responses)
  15. self.calls = []
  16. def request(self, **kwargs):
  17. self.calls.append(kwargs)
  18. response = self.responses.pop(0)
  19. if isinstance(response, Exception):
  20. raise response
  21. return response
  22. def test_lightrag_query_is_context_only_and_workspace_is_not_user_controlled():
  23. from app.core.knowledge.lightrag.client import LightRAGClient
  24. transport = Transport([Response({"response": "context text"})])
  25. client = LightRAGClient(
  26. base_url="http://lightrag:9621",
  27. api_key="internal-key",
  28. workspace="dataops-global-domain-a-g1",
  29. transport=transport,
  30. )
  31. result = client.query_context("上游是什么", mode="mix", limit=10)
  32. assert result == "context text"
  33. assert transport.calls[0]["json"]["only_need_context"] is True
  34. assert transport.calls[0]["json"]["mode"] == "mix"
  35. assert "workspace" not in transport.calls[0]["json"]
  36. def test_lightrag_circuit_breaker_opens_after_bounded_failures():
  37. from app.core.knowledge.lightrag.client import (
  38. LightRAGCircuitOpen,
  39. LightRAGClient,
  40. )
  41. transport = Transport([TimeoutError("one"), TimeoutError("two")])
  42. client = LightRAGClient(
  43. base_url="http://lightrag:9621",
  44. api_key="internal-key",
  45. workspace="dataops-global-domain-a-g1",
  46. transport=transport,
  47. failure_threshold=2,
  48. cooldown_seconds=60,
  49. )
  50. with pytest.raises(TimeoutError):
  51. client.health()
  52. with pytest.raises(TimeoutError):
  53. client.health()
  54. with pytest.raises(LightRAGCircuitOpen):
  55. client.health()
  56. assert len(transport.calls) == 2
  57. def test_lightrag_insert_uses_stable_external_id_as_idempotency_key():
  58. from app.core.knowledge.lightrag.client import LightRAGClient
  59. transport = Transport([Response({"track_id": "track-1"})])
  60. client = LightRAGClient(
  61. base_url="http://lightrag:9621",
  62. api_key="internal-key",
  63. workspace="dataops-global-domain-a-g1",
  64. transport=transport,
  65. )
  66. receipt = client.insert(
  67. external_document_id="DataFlow:source-1:2",
  68. content="canonical content",
  69. metadata={"point_keys": ["DataFlow/source-1/purpose"]},
  70. )
  71. assert receipt.track_id == "track-1"
  72. assert transport.calls[0]["headers"]["Idempotency-Key"] == "DataFlow:source-1:2"