Files
Jyotisha/tests/test_marriage_match_api.py
T
jesse-uxGrok (agent loop)Cursor
300a8842d3 fix(synastry): keep the scripts root file count inside the budget
Move the three local glue modules into scripts/marriage_match_service and point the invocation matrix at marriage_match.py. The upstream engine file stays where it is.

Checked the file-count and oracle contracts, the marriage-match tests, and a Windows full pytest. The 176 failures are python3-missing and path-separator noise; the named contracts passed.

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 21:33:30 +08:00

135 lines
5.2 KiB
Python

"""Marriage-match API glue: order, cache, and route registration."""
from __future__ import annotations
import json
import os
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
SCRIPTS = ROOT / "scripts"
if str(SCRIPTS) not in sys.path:
sys.path.insert(0, str(SCRIPTS))
from marriage_match import build_marriage_match_dossier
from marriage_match_service.api import (
CACHE_NAME,
MarriageMatchInputError,
compute_marriage_match,
compute_synastry_full_dossier,
)
import marriage_match_service.api as api
from marriage_match_service.full_dossier import RULES_VERSION
import api_heavy_compute_gate
def chart(asc, moon, venus, mars):
return {
"ascendant": {"longitude": asc},
"planets": {
"Moon": {"longitude": moon},
"Venus": {"longitude": venus},
"Mars": {"longitude": mars},
"Saturn": {"longitude": 210},
"Sun": {"longitude": 120},
"Rahu": {"longitude": 300},
"Ketu": {"longitude": 120},
},
}
def _pressure_signature(report):
people = []
for key in ("person_a", "person_b"):
rows = report["papasamya"][key]["active_placements"]
people.append(tuple(sorted(
(row["planet"], row["reference"], row["house"]) for row in rows
)))
return tuple(sorted(people))
def test_swapped_people_keep_pairing_kuja_and_pressure():
left = chart(10, 40, 70, 190)
right = chart(100, 130, 160, 250)
forward = build_marriage_match_dossier(left, right)
reverse = build_marriage_match_dossier(right, left)
assert forward["ashtakoota_36"]["international_core"]["scores"] == reverse["ashtakoota_36"]["international_core"]["scores"]
assert forward["ashtakoota_36"]["international_core"]["total_score"] == reverse["ashtakoota_36"]["international_core"]["total_score"]
assert forward["kuja_mangal_dosha"]["outcome"] == reverse["kuja_mangal_dosha"]["outcome"]
assert forward["kuja_mangal_dosha"]["person_a"]["active_reference_count"] == reverse["kuja_mangal_dosha"]["person_b"]["active_reference_count"]
assert _pressure_signature(forward) == _pressure_signature(reverse)
def test_snapshot_endpoint_rejects_a_non_object():
with pytest.raises(MarriageMatchInputError):
compute_marriage_match({"person_a": []})
def test_disk_cache_reuses_one_build(monkeypatch, tmp_path):
monkeypatch.setenv("GITHUB_SHA", "marriage-match-cache-test")
def cache_dir(name: str = "consult_full_data_cache"):
path = tmp_path / name
path.mkdir(parents=True, exist_ok=True)
return path
monkeypatch.setattr(api._cache, "cache_dir", cache_dir)
calls = {"n": 0}
def fake(_handler, _person_a, _person_b):
calls["n"] += 1
return {"rules_version": RULES_VERSION, "dossier": {"schema": "fixture"}, "raman_marriage_match": {}}
monkeypatch.setattr(
"marriage_match_service.api.build_synastry_full_dossier",
fake,
)
body = {
"person_a": {"year": 1990, "month": 1, "day": 2, "hour": 3, "minute": 4, "lat": 1, "lon": 2, "tz": 8},
"person_b": {"year": 1991, "month": 5, "day": 6, "hour": 7, "minute": 8, "lat": 3, "lon": 4, "tz": 8},
}
first = compute_synastry_full_dossier(object(), body)
second = compute_synastry_full_dossier(object(), body)
assert first == second
assert calls["n"] == 1
assert list((tmp_path / CACHE_NAME).glob("*.json"))
def test_missing_commit_does_not_reuse_the_disk_cache(monkeypatch):
monkeypatch.delenv("GITHUB_SHA", raising=False)
calls = {"n": 0}
def fake(_handler, _person_a, _person_b):
calls["n"] += 1
return {"rules_version": RULES_VERSION, "dossier": {}, "raman_marriage_match": {}}
monkeypatch.setattr("marriage_match_service.api.build_synastry_full_dossier", fake)
body = {
"person_a": {"year": 1990, "month": 1, "day": 2, "hour": 3, "minute": 4, "lat": 1, "lon": 2, "tz": 8},
"person_b": {"year": 1991, "month": 5, "day": 6, "hour": 7, "minute": 8, "lat": 3, "lon": 4, "tz": 8},
}
compute_synastry_full_dossier(object(), body)
compute_synastry_full_dossier(object(), body)
assert calls["n"] == 2
def test_routes_are_registered_and_the_dossier_is_heavy():
source = (ROOT / "scripts" / "jyotish_api_server.py").read_text(encoding="utf-8")
assert "elif path == '/api/marriage-match':" in source
assert "elif path == '/api/synastry_full_dossier':" in source
assert "/api/synastry_full_dossier" in api_heavy_compute_gate.HEAVY_COMPUTE_PATHS
assert "authorizeUsage" not in (ROOT / "frontend" / "src" / "lib" / "marriage-match-service.ts").read_text(encoding="utf-8")
assert not (ROOT / "scripts" / "synastry.py").exists()
def test_snapshot_golden_matches_the_engine():
fixture_path = ROOT / "frontend" / "tests" / "fixtures" / "marriage-match-snapshot.json"
payload = {"person_a": chart(12, 48, 96, 200), "person_b": chart(140, 210, 30, 300)}
result = compute_marriage_match(payload)
if os.environ.get("WRITE_MARRIAGE_MATCH_GOLDEN") == "1":
fixture_path.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
stored = json.loads(fixture_path.read_text(encoding="utf-8"))
assert result == stored