OpenEnvHackathon / tests /test_env.py
TheAllanB's picture
initial commit
5fde057
Raw
History Blame Contribute Delete
7.15 kB
"""
Sanity tests for the TICKETMELT environment.
Run with: pytest tests/ -v
These are NOT exhaustive — they're the minimum viable "does this work?" checks.
"""
import pytest
from src.environment import TicketmeltEnv
from src.models import Action
# ---------------------------------------------------------------------------
# Test 1: reset produces a valid observation
# ---------------------------------------------------------------------------
def test_reset_produces_valid_observation():
env = TicketmeltEnv(seed=42)
obs = env.reset()
assert obs.current_round == 0
assert obs.total_rounds == 8
assert obs.my_engineer_name == "trained"
assert len(obs.peer_progress) == 3
assert obs.my_service.fix_rounds_remaining > 0
assert obs.my_service.deadline_round >= obs.my_service.fix_rounds_remaining
assert obs.done is False
# ---------------------------------------------------------------------------
# Test 2: exactly one engineer is urgent per episode
# ---------------------------------------------------------------------------
def test_exactly_one_urgent_engineer():
env = TicketmeltEnv(seed=123)
env.reset()
state = env.state()
urgent_count = sum(
1 for s in state["services"].values() if s["urgency_flag"]
)
assert urgent_count == 1
# ---------------------------------------------------------------------------
# Test 3: collisions produce no progress
# ---------------------------------------------------------------------------
def test_collision_produces_no_progress():
env = TicketmeltEnv(seed=0)
obs = env.reset()
initial_remaining = obs.my_service.fix_rounds_remaining
# Trained agent picks PROD_A. All three peers are "eager" → also pick PROD_A.
# Guaranteed collision.
action = Action(commitment="DEPLOY_PROD_A", channel_msg="going to A")
obs, reward, done, info = env.step(action)
# My service should not have progressed
assert obs.my_service.fix_rounds_remaining == initial_remaining
# Collision should be recorded in history
assert len(obs.history) == 1
assert "PROD_A" in obs.history[0].collisions
# ---------------------------------------------------------------------------
# Test 4: solo deploy advances the service
# ---------------------------------------------------------------------------
def test_solo_deploy_advances_service():
env = TicketmeltEnv(seed=7)
obs = env.reset()
initial_remaining = obs.my_service.fix_rounds_remaining
# All three peers go to PROD_A (eager). Trained goes to PROD_B alone.
action = Action(commitment="DEPLOY_PROD_B", channel_msg="going to B")
obs, reward, done, info = env.step(action)
# My service should have advanced
assert obs.my_service.fix_rounds_remaining == initial_remaining - 1
# ---------------------------------------------------------------------------
# Test 5: episode terminates at total_rounds
# ---------------------------------------------------------------------------
def test_episode_terminates():
env = TicketmeltEnv(seed=99, total_rounds=3)
env.reset()
for _ in range(3):
obs, reward, done, info = env.step(
Action(commitment="MONITOR", channel_msg="")
)
assert done is True
# ---------------------------------------------------------------------------
# Test 6: malformed commitment defaults to MONITOR
# ---------------------------------------------------------------------------
def test_invalid_commitment_defaults_to_monitor():
env = TicketmeltEnv(seed=5)
env.reset()
# Pass a garbage commitment
bad_action = Action(commitment="DEPLOY_NUKE", channel_msg="hax") # type: ignore
obs, reward, done, info = env.step(bad_action)
assert obs.history[0].commitments["trained"] == "MONITOR"
# ---------------------------------------------------------------------------
# Test 7: reward is zero until episode ends
# ---------------------------------------------------------------------------
def test_intermediate_reward_is_zero():
env = TicketmeltEnv(seed=11, total_rounds=4)
env.reset()
rewards_collected = []
for _ in range(3): # stop one round before end
_, reward, done, _ = env.step(Action(commitment="MONITOR", channel_msg=""))
rewards_collected.append(reward)
if done:
break
# All but possibly the last should be zero
assert all(r == 0.0 for r in rewards_collected[:-1])
# ---------------------------------------------------------------------------
# Test 8: full-episode reward is in {0.0, 1.0}
# ---------------------------------------------------------------------------
def test_final_reward_is_binary():
env = TicketmeltEnv(seed=31)
env.reset()
final_reward = 0.0
while True:
_, reward, done, info = env.step(Action(commitment="MONITOR", channel_msg=""))
if done:
final_reward = reward
break
assert final_reward in (0.0, 1.0)
# ---------------------------------------------------------------------------
# Probe: always-eager agent should score poorly
# ---------------------------------------------------------------------------
def test_probe_always_deploy_a_scores_poorly():
"""An agent that always deploys to PROD_A (like the dumb peers) should
collide constantly and score low. This is our 'reward not hackable by
doing nothing' probe."""
low_score_episodes = 0
total_episodes = 10
for seed in range(total_episodes):
env = TicketmeltEnv(seed=seed)
env.reset()
while True:
_, reward, done, info = env.step(
Action(commitment="DEPLOY_PROD_A", channel_msg="A")
)
if done:
if reward == 0.0:
low_score_episodes += 1
break
# Expect: always-deploy-A should fail (reward=0) in most episodes
assert low_score_episodes >= 7, (
f"Always-deploy-A agent scored well in {total_episodes - low_score_episodes}/"
f"{total_episodes} episodes — reward may be too easy to game"
)
# ---------------------------------------------------------------------------
# Probe: always-monitor agent should also score poorly
# ---------------------------------------------------------------------------
def test_probe_always_monitor_scores_poorly():
"""An agent that never deploys can't restore its service and should get
low R1. This probe ensures rewards aren't gameable by doing nothing."""
low_score_episodes = 0
total_episodes = 10
for seed in range(total_episodes):
env = TicketmeltEnv(seed=seed)
env.reset()
while True:
_, reward, done, info = env.step(
Action(commitment="MONITOR", channel_msg="")
)
if done:
if reward == 0.0:
low_score_episodes += 1
break
assert low_score_episodes >= 8, (
f"Always-monitor agent scored well in {total_episodes - low_score_episodes}/"
f"{total_episodes} episodes — rewards may be gameable by doing nothing"
)