mattrguerra/meridian-crm-mcpmainPrivate on GitHub, published here in full

conftest.py

Language Python3.1 KB98 lines

tests/conftest.py

  1. """Test setup: server.py reads its configuration at import time and exits when
  2. BITRIX_WEBHOOK_URL is unset, so the environment is fixed here, before any test
  3. module imports it. Data (logs, schema snapshots) goes to a throwaway directory."""
  4. import os
  5. import sys
  6. import tempfile
  7. from pathlib import Path
  8. import pytest
  9. os.environ["BITRIX_WEBHOOK_URL"] = "https://example.invalid/rest/1/x"
  10. os.environ["BITRIX_DATA_DIR"] = tempfile.mkdtemp(prefix="bitrix-mcp-tests-")
  11. os.environ["BITRIX_LOCAL_TZ"] = "America/Chicago"
  12. os.environ["BITRIX_WRITES"] = "on"
  13. os.environ["BITRIX_WRITE_PARTIES"] = "on"
  14. os.environ["BITRIX_LOG_ARGS"] = "redact"
  15. sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
  16. import server # noqa: E402
  17. # Per-process caches that must not leak between tests. Listed by name and
  18. # reset only if present, so the fixture does not depend on how the server
  19. # organises them internally.
  20. _CACHES = ("_STATUS_CACHE", "_PIPELINES_CACHE", "_FIELDS_CACHE", "_USER_CACHE",
  21. "_USER_NAMES", "_ALLOWED_CATS", "_FUNNEL_NAMES")
  22. @pytest.fixture(autouse=True)
  23. def _fresh_caches():
  24. def reset():
  25. for name in _CACHES:
  26. if not hasattr(server, name):
  27. continue
  28. value = getattr(server, name)
  29. if isinstance(value, dict):
  30. value.clear()
  31. else:
  32. setattr(server, name, None)
  33. reset()
  34. yield
  35. reset()
  36. class FakeBitrix:
  37. """Stands in for server.bitrix_call: records every (method, params) pair
  38. and answers from a script keyed by method name. A scripted value may be a
  39. list (consumed in order), an exception instance (raised), or a callable
  40. taking params."""
  41. def __init__(self, script: dict | None = None):
  42. self.script = dict(script or {})
  43. self.calls: list[tuple[str, dict]] = []
  44. async def __call__(self, method, params=None, envelope=False):
  45. self.calls.append((method, params))
  46. if method not in self.script:
  47. raise AssertionError(f"unexpected Bitrix call: {method} {params!r}")
  48. answer = self.script[method]
  49. if isinstance(answer, list) and answer and isinstance(answer[0], _Seq):
  50. answer = answer.pop(0).value
  51. if isinstance(answer, BaseException):
  52. raise answer
  53. if callable(answer):
  54. return answer(params)
  55. return answer
  56. @property
  57. def methods(self) -> list[str]:
  58. return [m for m, _ in self.calls]
  59. class _Seq:
  60. def __init__(self, value):
  61. self.value = value
  62. def seq(*values):
  63. """Script helper: successive answers for repeated calls to one method."""
  64. return [_Seq(v) for v in values]
  65. @pytest.fixture
  66. def fake_bitrix(monkeypatch):
  67. def install(script=None):
  68. fake = FakeBitrix(script)
  69. monkeypatch.setattr(server, "bitrix_call", fake)
  70. return fake
  71. return install
  72. @pytest.fixture
  73. def logged(monkeypatch):
  74. """Capture log_call records instead of writing calls.jsonl."""
  75. records: list[tuple[str, dict, str]] = []
  76. monkeypatch.setattr(server, "log_call", lambda tool, args, summary: records.append((tool, args, summary)))
  77. return records