From b362cc35bf612676b2bf4ad56b3f6056eaed00d7 Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Thu, 27 Aug 2026 07:37:01 +0700 Subject: [PATCH] [verified] Add API tests for /api/v1/learning/factors + configurable history dir Closes reviewer suggestion (deleg_5dd358e3): adds coverage for the factor readiness endpoint (n_points / learnable / last_value / ordering) and the min_points 400 validation. FACTOR_HISTORY_DIR is now configurable via app config so tests (and deploy) can point the history store at a chosen path instead of a hardcoded data dir. 236 tests pass. --- backend/app/__init__.py | 4 +++- backend/tests/test_api.py | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/backend/app/__init__.py b/backend/app/__init__.py index ba7ad54..0290e7f 100644 --- a/backend/app/__init__.py +++ b/backend/app/__init__.py @@ -790,7 +790,9 @@ def create_app(config: dict[str, Any] | None = None) -> Flask: """ from app import factors as factors_mod from app.factor_history import FactorHistory - fh = FactorHistory(Path(__file__).resolve().parents[1] / "data" / "factor_history") + hist_dir = app.config.get("FACTOR_HISTORY_DIR") or ( + Path(__file__).resolve().parents[1] / "data" / "factor_history") + fh = FactorHistory(hist_dir) try: min_points = max(int(request.args.get("min_points", "12")), 0) except (TypeError, ValueError): diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py index 0675f9a..2fe6fb2 100644 --- a/backend/tests/test_api.py +++ b/backend/tests/test_api.py @@ -495,5 +495,30 @@ class ApiTests(unittest.TestCase): second_app = create_app(config) entries = second_app.test_client().get("/api/v1/paper/ledger").get_json()["entries"] self.assertEqual([entry["entry_id"] for entry in entries], [entry_id]) + + def test_learning_factors_reports_points_and_learnable(self): + with tempfile.TemporaryDirectory() as temp_dir: + from app.factor_history import FactorHistory + fh = FactorHistory(Path(temp_dir)) + for i in range(3): + fh.record("macro_consumption", 3.0 + i, ts=f"2026-0{i+1}-01T00:00:00+00:00") + app = create_app({"TESTING": True, "SNAPSHOT": self.snapshot, + "FACTOR_HISTORY_DIR": Path(temp_dir)}) + resp = app.test_client().get("/api/v1/learning/factors?min_points=2") + self.assertEqual(resp.status_code, 200) + body = resp.get_json() + self.assertEqual(body["min_points"], 2) + mc = next(r for r in body["factors"] if r["factor_key"] == "macro_consumption") + self.assertEqual(mc["n_points"], 3) + self.assertTrue(mc["learnable"]) + self.assertEqual(mc["last_value"], 5.0) + # sorted by n_points desc: macro_consumption (3) should be first + self.assertEqual(body["factors"][0]["factor_key"], "macro_consumption") + + def test_learning_factors_rejects_bad_min_points(self): + app = create_app({"TESTING": True, "SNAPSHOT": self.snapshot}) + resp = app.test_client().get("/api/v1/learning/factors?min_points=abc") + self.assertEqual(resp.status_code, 400) + if __name__ == "__main__": unittest.main()