Spaces:
Sleeping
Sleeping
| """Tests for per-episode randomization — seed determinism, fee/budget jitter.""" | |
| import sys | |
| import os | |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) | |
| from server.permit_env_environment import PermitEnvironment, TASKS | |
| def test_same_seed_same_result(): | |
| """Two resets with the same seed should produce identical observations.""" | |
| env = PermitEnvironment() | |
| obs_a = env.reset(seed=42, task_name="medium_cafe") | |
| obs_b = env.reset(seed=42, task_name="medium_cafe") | |
| assert obs_a.budget_remaining == obs_b.budget_remaining | |
| assert list(obs_a.permits.keys()) == list(obs_b.permits.keys()) | |
| for pid in obs_a.permits: | |
| assert obs_a.permits[pid]["fee"] == obs_b.permits[pid]["fee"] | |
| def test_different_seed_different_fees(): | |
| """Two resets with different seeds should produce different fees.""" | |
| env = PermitEnvironment() | |
| obs_a = env.reset(seed=1, task_name="easy_foodtruck") | |
| obs_b = env.reset(seed=2, task_name="easy_foodtruck") | |
| fees_a = {pid: p["fee"] for pid, p in obs_a.permits.items()} | |
| fees_b = {pid: p["fee"] for pid, p in obs_b.permits.items()} | |
| # At least one fee should differ (probability of all equal ≈ 0) | |
| assert fees_a != fees_b, "Fees should differ between seeds" | |
| def test_different_seed_different_budget(): | |
| """Budget should be jittered between seeds.""" | |
| env = PermitEnvironment() | |
| obs_a = env.reset(seed=10, task_name="hard_restaurant") | |
| obs_b = env.reset(seed=20, task_name="hard_restaurant") | |
| assert obs_a.budget_remaining != obs_b.budget_remaining | |
| def test_permit_order_shuffled(): | |
| """Permit iteration order should vary between seeds.""" | |
| env = PermitEnvironment() | |
| orders = [] | |
| for seed in range(10): | |
| obs = env.reset(seed=seed, task_name="hard_restaurant") | |
| orders.append(list(obs.permits.keys())) | |
| # At least 2 of 10 orders should be different | |
| unique_orders = set(tuple(o) for o in orders) | |
| assert len(unique_orders) >= 2, "Permit order should vary across seeds" | |
| def test_fee_jitter_within_bounds(): | |
| """Fees should be within +/-20% of the base fee.""" | |
| env = PermitEnvironment() | |
| base_fees = { | |
| pid: cfg["fee"] | |
| for pid, cfg in TASKS["easy_foodtruck"]["permits"].items() | |
| } | |
| for seed in range(20): | |
| obs = env.reset(seed=seed, task_name="easy_foodtruck") | |
| for pid, p in obs.permits.items(): | |
| base = base_fees[pid] | |
| low = base * 0.80 - 0.01 # tiny epsilon for float rounding | |
| high = base * 1.20 + 0.01 | |
| assert low <= p["fee"] <= high, ( | |
| f"seed={seed} {pid} fee={p['fee']} outside [{low:.2f}, {high:.2f}]" | |
| ) | |
| def test_budget_jitter_within_bounds(): | |
| """Budget should be within +/-10% of the base budget.""" | |
| base_budget = TASKS["medium_cafe"]["budget"] | |
| env = PermitEnvironment() | |
| for seed in range(20): | |
| obs = env.reset(seed=seed, task_name="medium_cafe") | |
| low = base_budget * 0.90 - 0.01 | |
| high = base_budget * 1.10 + 0.01 | |
| assert low <= obs.budget_remaining <= high, ( | |
| f"seed={seed} budget={obs.budget_remaining} outside [{low:.2f}, {high:.2f}]" | |
| ) | |