SupportOps / tests /test_env.py
prathvi9607's picture
done phase 1
9c1645f
Raw History Blame Contribute Delete
5.83 kB
"""
Tests for SupportOpsArena environment core functionality.
"""
import pytest
from env.environment import SupportOpsArena
from env.actions import ActionType
from env.state import TaskLevel
from adversary.adversary import AdaptiveAdversary
class TestEnvironmentBasics:
"""Test basic environment functionality."""
@pytest.mark.asyncio
async def test_environment_initialization(self):
"""Test environment can be created."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
assert env is not None
@pytest.mark.asyncio
async def test_reset_easy(self):
"""Test reset for easy task."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
obs = await env.reset(task_level="easy", seed=42)
assert obs.task_level == TaskLevel.EASY
assert obs.step_count == 0
assert len(obs.system_logs) > 0
assert obs.escalation_allowed == False
@pytest.mark.asyncio
async def test_reset_medium(self):
"""Test reset for medium task."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
obs = await env.reset(task_level="medium", seed=42)
assert obs.task_level == TaskLevel.MEDIUM
assert obs.step_count == 0
@pytest.mark.asyncio
async def test_reset_hard(self):
"""Test reset for hard task."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
obs = await env.reset(task_level="hard", seed=42)
assert obs.task_level == TaskLevel.HARD
assert obs.step_count == 0
@pytest.mark.asyncio
async def test_step_basic_action(self):
"""Test taking a basic step."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
obs = await env.reset(task_level="easy", seed=42)
result = await env.step(ActionType.INSPECT_LOGS)
assert result.observation.step_count == 1
assert result.reward != 0.0 # Should get diagnostic reward
assert result.done == False
@pytest.mark.asyncio
async def test_invalid_task_level(self):
"""Test reset with invalid task level raises error."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
with pytest.raises(ValueError):
await env.reset(task_level="invalid")
@pytest.mark.asyncio
async def test_episode_done_on_resolve(self):
"""Test episode ends when ticket is resolved."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
await env.reset(task_level="easy", seed=42)
# Take a few diagnostic actions
await env.step(ActionType.INSPECT_LOGS)
await env.step(ActionType.CHECK_AUTHENTICATION)
await env.step(ActionType.INSPECT_NETWORK)
# Resolve ticket
result = await env.step(ActionType.RESOLVE_TICKET)
assert result.done == True
assert "root_cause" in result.info
@pytest.mark.asyncio
async def test_state_method(self):
"""Test state() method returns full state."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
await env.reset(task_level="easy", seed=42)
state = await env.state()
assert state.observation is not None
assert state.hidden is not None
assert state.episode_id is not None
@pytest.mark.asyncio
async def test_escalation_unlock(self):
"""Test escalation is unlocked after enough diagnostics."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
obs = await env.reset(task_level="easy", seed=42)
assert obs.escalation_allowed == False
# Take 3 diagnostic actions (unlock threshold for easy)
result1 = await env.step(ActionType.INSPECT_LOGS)
result2 = await env.step(ActionType.CHECK_AUTHENTICATION)
result3 = await env.step(ActionType.INSPECT_NETWORK)
# Should now be unlocked
assert result3.observation.escalation_allowed == True
@pytest.mark.asyncio
async def test_step_without_reset_raises_error(self):
"""Test that step without reset raises error."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
with pytest.raises(RuntimeError):
await env.step(ActionType.INSPECT_LOGS)
class TestRewardSystem:
"""Test reward calculation."""
@pytest.mark.asyncio
async def test_diagnostic_action_reward(self):
"""Test diagnostic actions give positive reward."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
await env.reset(task_level="easy", seed=42)
result = await env.step(ActionType.INSPECT_LOGS)
assert result.reward > 0 # Should get diagnostic bonus
assert "DIAGNOSTIC_ACTION" in str(result.info.get("reward_breakdown", {}))
@pytest.mark.asyncio
async def test_redundant_action_penalty(self):
"""Test redundant actions are penalized."""
adversary = AdaptiveAdversary()
env = SupportOpsArena(adversary=adversary)
await env.reset(task_level="easy", seed=42)
# Take same action twice
result1 = await env.step(ActionType.INSPECT_LOGS)
result2 = await env.step(ActionType.INSPECT_LOGS)
# Second time should have penalty
assert "REDUNDANT_ACTION" in str(result2.info.get("reward_breakdown", {}))