Spaces:
Sleeping
Sleeping
| """ | |
| Tests for the DevOps RL Environment. | |
| """ | |
| import pytest | |
| from devops_env.env import DevOpsEnv | |
| from scenarios.registry import ScenarioRegistry, Scenario | |
| def _make_test_registry(): | |
| """Create a minimal registry for testing.""" | |
| registry = ScenarioRegistry() | |
| registry.register(Scenario( | |
| id="test_missing_pkg", | |
| level=1, | |
| description="Test: missing package", | |
| initial_state={}, | |
| success_condition=lambda out: "successfully installed" in out.lower(), | |
| hint_commands=["pip install testpkg"], | |
| error_fingerprint=r"ModuleNotFoundError", | |
| initial_error_log="ModuleNotFoundError: No module named 'testpkg'", | |
| )) | |
| return registry | |
| class TestDevOpsEnv: | |
| """Tests for the OpenEnv-style environment.""" | |
| def test_reset_returns_observation(self): | |
| registry = _make_test_registry() | |
| env = DevOpsEnv(scenario_registry=registry, max_steps=5) | |
| obs, info = env.reset(options={"scenario_id": "test_missing_pkg"}) | |
| assert "error_log" in obs | |
| assert "command_history" in obs | |
| assert "step_count" in obs | |
| assert "scenario_id" in obs | |
| assert "error_type" in obs | |
| assert "error_confidence" in obs | |
| assert "is_terminal" in obs | |
| assert "solved" in obs | |
| assert obs["scenario_id"] == "test_missing_pkg" | |
| assert obs["step_count"] == 0 | |
| env.close() | |
| def test_step_returns_correct_tuple(self): | |
| registry = _make_test_registry() | |
| env = DevOpsEnv(scenario_registry=registry, max_steps=5) | |
| obs, _ = env.reset(options={"scenario_id": "test_missing_pkg"}) | |
| result = env.step("echo hello") | |
| assert len(result) == 5 # obs, reward, terminated, truncated, info | |
| obs, reward, terminated, truncated, info = result | |
| assert isinstance(reward, float) | |
| assert isinstance(terminated, bool) | |
| assert isinstance(truncated, bool) | |
| assert isinstance(info, dict) | |
| env.close() | |
| def test_max_steps_truncates(self): | |
| registry = _make_test_registry() | |
| env = DevOpsEnv(scenario_registry=registry, max_steps=3) | |
| env.reset(options={"scenario_id": "test_missing_pkg"}) | |
| truncated = False | |
| for i in range(3): | |
| _, _, terminated, truncated, _ = env.step("echo step") | |
| if terminated or truncated: | |
| break | |
| assert truncated or terminated # Should end by step 3 | |
| env.close() | |
| def test_error_type_classified(self): | |
| registry = _make_test_registry() | |
| env = DevOpsEnv(scenario_registry=registry) | |
| obs, info = env.reset(options={"scenario_id": "test_missing_pkg"}) | |
| assert obs["error_type"] == "missing_package" | |
| env.close() | |
| def test_episode_summary(self): | |
| registry = _make_test_registry() | |
| env = DevOpsEnv(scenario_registry=registry, max_steps=2) | |
| env.reset(options={"scenario_id": "test_missing_pkg"}) | |
| env.step("echo test") | |
| summary = env.get_episode_summary() | |
| assert summary["scenario_id"] == "test_missing_pkg" | |
| assert summary["level"] == 1 | |
| assert len(summary["steps"]) == 1 | |
| env.close() | |
| def test_cannot_step_after_done(self): | |
| registry = _make_test_registry() | |
| env = DevOpsEnv(scenario_registry=registry, max_steps=1) | |
| env.reset(options={"scenario_id": "test_missing_pkg"}) | |
| env.step("echo done") | |
| with pytest.raises(RuntimeError): | |
| env.step("echo again") | |
| env.close() | |
| class TestScenarioRegistry: | |
| """Tests for the scenario registry.""" | |
| def test_register_and_get(self): | |
| registry = ScenarioRegistry() | |
| scenario = Scenario( | |
| id="test1", level=1, description="test", | |
| initial_state={}, success_condition=lambda x: True, | |
| hint_commands=["echo"], error_fingerprint="test", | |
| ) | |
| registry.register(scenario) | |
| assert registry.get("test1").id == "test1" | |
| def test_duplicate_registration_raises(self): | |
| registry = ScenarioRegistry() | |
| scenario = Scenario( | |
| id="dup", level=1, description="test", | |
| initial_state={}, success_condition=lambda x: True, | |
| hint_commands=["echo"], error_fingerprint="test", | |
| ) | |
| registry.register(scenario) | |
| with pytest.raises(ValueError): | |
| registry.register(scenario) | |
| def test_get_by_level(self): | |
| registry = ScenarioRegistry() | |
| registry.register_defaults() | |
| level1 = registry.get_by_level(1) | |
| assert len(level1) >= 3 | |
| assert all(s.level == 1 for s in level1) | |
| def test_get_random(self): | |
| registry = ScenarioRegistry() | |
| registry.register_defaults() | |
| scenario = registry.get_random(level=1) | |
| assert scenario.level == 1 | |
| def test_register_defaults(self): | |
| registry = ScenarioRegistry() | |
| registry.register_defaults() | |
| assert registry.count >= 9 # 3+ per level | |