test_basic.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. from __future__ import annotations
  2. from pathlib import Path
  3. from fastapi.testclient import TestClient
  4. from src.ephemeris_mcp.server import (
  5. _parse_datetime,
  6. create_app,
  7. get_constellation_at_ecliptic,
  8. get_moon_phase,
  9. get_lunar_state,
  10. get_planetary_positions,
  11. get_sky_state,
  12. get_sidereal_time,
  13. get_solar_events,
  14. list_available_bodies,
  15. )
  16. from src.ephemeris_mcp.storage import EphemerisCache, cache_key
  17. def test_parse_datetime_accepts_iso_zulu() -> None:
  18. jd = _parse_datetime("2026-05-10T12:00:00Z")
  19. assert isinstance(jd, float)
  20. assert 2461170 < jd < 2461172
  21. def test_cache_roundtrip(tmp_path: Path) -> None:
  22. cache = EphemerisCache(tmp_path / "cache.sqlite3")
  23. key = cache_key("demo", lon=8.5, lat=47.3)
  24. assert cache.get(key) is None
  25. cache.set(key, {"ok": True, "value": 42}, ttl=60)
  26. assert cache.get(key) == {"ok": True, "value": 42}
  27. def test_health_endpoint_smoke() -> None:
  28. client = TestClient(create_app())
  29. res = client.get("/health")
  30. assert res.status_code == 200
  31. data = res.json()
  32. assert data == {"ok": True, "server": "ephemeris-mcp", "port": 7015}
  33. def test_root_lists_core_tools() -> None:
  34. client = TestClient(create_app())
  35. res = client.get("/")
  36. assert res.status_code == 200
  37. data = res.json()
  38. assert data["server"] == "ephemeris-mcp"
  39. assert data["status"] == "ready"
  40. assert data["tools"] == [
  41. "get_planetary_positions",
  42. "get_solar_events",
  43. "get_lunar_state",
  44. "get_moon_phase",
  45. "get_sidereal_time",
  46. "get_constellation_at_ecliptic",
  47. "list_available_bodies",
  48. "get_sky_state",
  49. ]
  50. assert data["mcp"] == {"sse": "/mcp/sse", "messages": "/mcp/messages"}
  51. def test_list_available_bodies_shape() -> None:
  52. result = list_available_bodies()
  53. assert "bodies" in result
  54. names = {body["name"] for body in result["bodies"]}
  55. assert "sun" in names
  56. assert "moon" in names
  57. assert "mars" in names
  58. def test_tool_shapes_are_present() -> None:
  59. body_positions = get_planetary_positions(datetime="2026-05-10T12:00:00Z")
  60. topocentric_positions = get_planetary_positions(
  61. datetime="2026-05-10T12:00:00Z",
  62. geocentric=False,
  63. lat=47.0,
  64. lon=8.0,
  65. elevation=500.0,
  66. )
  67. solar_events = get_solar_events(date="2026-05-10", lat=47.0, lon=8.0)
  68. lunar_state = get_lunar_state(datetime="2026-05-10T12:00:00Z")
  69. sidereal_time = get_sidereal_time(datetime="2026-05-10T12:00:00Z")
  70. constellation = get_constellation_at_ecliptic(120.0)
  71. sky_state = get_sky_state(datetime="2026-05-10T12:00:00Z", lat=47.0, lon=8.0, elevation=500.0)
  72. assert body_positions["input"]["datetime"] == "2026-05-10T12:00:00Z"
  73. assert "bodies" in body_positions
  74. assert sum(1 for body in body_positions["bodies"] if "error" in body) <= 1
  75. assert sum(1 for body in topocentric_positions["bodies"] if "error" in body) <= 1
  76. assert solar_events["input"]["date"] == "2026-05-10"
  77. assert "events_jd" in solar_events
  78. assert "lunar_state" in lunar_state
  79. assert "greenwich_sidereal_time" in sidereal_time
  80. assert constellation["input"]["ecliptic_lon"] == 120.0
  81. assert "planetary_positions" in sky_state
  82. assert "solar_events" in sky_state
  83. assert "sidereal_time" in sky_state
  84. def test_moon_phase_tool_shape() -> None:
  85. moon_phase = get_moon_phase(datetime="2026-05-10T12:00:00Z")
  86. assert moon_phase["phase_name"]
  87. assert 0.0 <= moon_phase["illumination_fraction"] <= 1.0
  88. assert moon_phase["input"]["datetime"] == "2026-05-10T12:00:00Z"
  89. assert moon_phase["phase_name"] == "Last Quarter"
  90. assert moon_phase["next_major_phase"]["phase_name"] == "New Moon"
  91. assert moon_phase["next_major_phase"]["at_utc"] == "2026-05-16T20:01:04Z"
  92. assert moon_phase["next_major_phase"]["in_text"]
  93. assert "d" in moon_phase["next_major_phase"]["in_text"] or "h" in moon_phase["next_major_phase"]["in_text"] or "m" in moon_phase["next_major_phase"]["in_text"]
  94. def test_default_location_can_be_configured(monkeypatch) -> None:
  95. monkeypatch.setenv("EPHEMERIS_DEFAULT_LAT", "48.2")
  96. monkeypatch.setenv("EPHEMERIS_DEFAULT_LON", "16.37")
  97. from importlib import reload
  98. import src.ephemeris_mcp.config as config
  99. import src.ephemeris_mcp.server as server
  100. reload(config)
  101. server = reload(server)
  102. result = server.get_moon_phase(datetime="2026-05-10T12:00:00Z")
  103. assert result["input"]["lat"] == 48.2
  104. assert result["input"]["lon"] == 16.37