"""Gate defaults to dry-run / blocked; live only with dual confirm + STRATEGY_ID.""" from __future__ import annotations import os import unittest from unittest import mock from src.gate import LIVE_CONFIRM_VALUE, attempt_live_submit, evaluate_gate class FakeClient: def __init__(self) -> None: self.calls = [] def submit(self, payload): self.calls.append(payload) return {"task_id": "fake-1"} class TestGate(unittest.TestCase): def setUp(self): self.counter = mock.patch('src.gate._submit_count', 0) self.counter.start() self.addCleanup(self.counter.stop) self.env = mock.patch.dict(os.environ, {}, clear=True) self.env.start() self.addCleanup(self.env.stop) def test_queue_and_process_limit(self): client = FakeClient() with mock.patch.dict(os.environ, { 'STRATEGY_ID': 'sid', 'ALLOW_LIVE_SUBMIT': '1', 'LIVE_CONFIRM': LIVE_CONFIRM_VALUE, 'ASYNC_QUEUE_DEPTH': '95' }): self.assertIn('≥95', attempt_live_submit({}, client)['reason']) self.assertEqual(client.calls, []) os.environ['ASYNC_QUEUE_DEPTH'] = '94' self.assertTrue(attempt_live_submit({}, client)['submitted']) self.assertFalse(attempt_live_submit({}, client)['submitted']) self.assertEqual(len(client.calls), 1) def _clear_gate_env(self): return mock.patch.dict( os.environ, { "STRATEGY_ID": "sid-1", "ALLOW_LIVE_SUBMIT": "0", "LIVE_CONFIRM": "", }, clear=False, ) def test_default_dry_run(self) -> None: with self._clear_gate_env(): d = evaluate_gate() self.assertFalse(d.allowed) self.assertEqual(d.mode, "dry-run") def test_missing_strategy_blocked(self) -> None: env = { "ALLOW_LIVE_SUBMIT": "1", "LIVE_CONFIRM": LIVE_CONFIRM_VALUE, } # Remove STRATEGY_ID base = {k: v for k, v in os.environ.items() if k != "STRATEGY_ID"} base.update(env) with mock.patch.dict(os.environ, base, clear=True): d = evaluate_gate() self.assertFalse(d.allowed) self.assertEqual(d.mode, "blocked") def test_allow_without_confirm_blocked(self) -> None: with mock.patch.dict( os.environ, { "STRATEGY_ID": "sid-1", "ALLOW_LIVE_SUBMIT": "1", "LIVE_CONFIRM": "YES", }, clear=False, ): d = evaluate_gate() self.assertFalse(d.allowed) self.assertEqual(d.mode, "blocked") def test_dual_gate_opens(self) -> None: with mock.patch.dict( os.environ, { "STRATEGY_ID": "sid-1", "ALLOW_LIVE_SUBMIT": "1", "LIVE_CONFIRM": LIVE_CONFIRM_VALUE, }, clear=False, ): d = evaluate_gate() self.assertTrue(d.allowed) self.assertEqual(d.mode, "live") def test_open_gate_without_client_still_blocked(self) -> None: """Phase2: an open gate never constructs a network client.""" with mock.patch.dict( os.environ, { "STRATEGY_ID": "sid-1", "ALLOW_LIVE_SUBMIT": "1", "LIVE_CONFIRM": LIVE_CONFIRM_VALUE, }, clear=False, ): result = attempt_live_submit({"modelAddress": "x/y"}) self.assertFalse(result["submitted"]) self.assertIn("no real", result["reason"].lower()) self.assertEqual(result["mode"], "blocked") self.assertFalse(result["ok"]) def test_prd_example_and_whitespace_id_never_submit(self) -> None: cases = [ {"ALLOW_LIVE_SUBMIT": "true", "LIVE_CONFIRM": LIVE_CONFIRM_VALUE}, {"ALLOW_LIVE_SUBMIT": "1", "LIVE_CONFIRM": "", "CONFIRM_LIVE": "YES"}, {"ALLOW_LIVE_SUBMIT": "1", "LIVE_CONFIRM": LIVE_CONFIRM_VALUE, "STRATEGY_ID": " "}, ] for overrides in cases: with self.subTest(overrides=overrides): client = FakeClient() env = {"STRATEGY_ID": "sid-test", **overrides} with mock.patch.dict(os.environ, env, clear=True): result = attempt_live_submit({}, client=client) self.assertFalse(result["submitted"]) self.assertFalse(result["ok"]) self.assertEqual(client.calls, []) self.assertTrue(result["reason"]) def test_injected_fake_client(self) -> None: client = FakeClient() with mock.patch.dict( os.environ, { "STRATEGY_ID": "sid-1", "ALLOW_LIVE_SUBMIT": "1", "LIVE_CONFIRM": LIVE_CONFIRM_VALUE, }, clear=False, ): result = attempt_live_submit({"modelAddress": "x/y"}, client=client) self.assertTrue(result["submitted"]) self.assertEqual(len(client.calls), 1) def test_default_attempt_rejects(self) -> None: client = FakeClient() with self._clear_gate_env(): result = attempt_live_submit({"modelAddress": "x/y"}, client=client) self.assertFalse(result["submitted"]) self.assertEqual(len(client.calls), 0) if __name__ == "__main__": unittest.main()