Spaces:
Sleeping
Sleeping
| """Tests for CloudSenseEnv.""" | |
| import pytest | |
| from env.environment import CloudSenseEnv | |
| def env(): | |
| e = CloudSenseEnv() | |
| yield e | |
| e.close() | |
| class TestReset: | |
| def test_reset_easy(self, env): | |
| obs = env.reset("startup-cleanup") | |
| assert len(obs.resources) == 7 | |
| assert obs.monthly_cost_current > 0 | |
| assert obs.step_number == 0 | |
| assert obs.task_id == "startup-cleanup" | |
| def test_reset_medium(self, env): | |
| obs = env.reset("mid-size-audit") | |
| assert len(obs.resources) == 15 | |
| def test_reset_hard(self, env): | |
| obs = env.reset("enterprise-finops") | |
| assert len(obs.resources) == 40 | |
| def test_reset_invalid_task(self, env): | |
| with pytest.raises(ValueError, match="Unknown task"): | |
| env.reset("nonexistent") | |
| def test_reset_clears_state(self, env): | |
| env.reset("startup-cleanup") | |
| env.step({"action_type": "skip_resource", "resource_id": "res-easy-001", "reasoning": "test"}) | |
| obs = env.reset("startup-cleanup") | |
| assert obs.step_number == 0 | |
| assert len(obs.actions_taken) == 0 | |
| class TestStep: | |
| def test_valid_step(self, env): | |
| env.reset("startup-cleanup") | |
| result = env.step({ | |
| "action_type": "rightsize_resource", | |
| "resource_id": "res-easy-001", | |
| "new_config": {"instance_type": "t3.small"}, | |
| "reasoning": "CPU at 4%, oversized", | |
| }) | |
| assert result.reward > 0 | |
| assert result.done is False | |
| assert result.observation.step_number == 1 | |
| def test_invalid_resource(self, env): | |
| env.reset("startup-cleanup") | |
| result = env.step({ | |
| "action_type": "skip_resource", | |
| "resource_id": "nonexistent", | |
| "reasoning": "test", | |
| }) | |
| assert result.reward == 0.0 | |
| assert result.observation.last_action_error is not None | |
| def test_invalid_action_type(self, env): | |
| env.reset("startup-cleanup") | |
| result = env.step({ | |
| "action_type": "invalid_action", | |
| "resource_id": "res-easy-001", | |
| "reasoning": "test", | |
| }) | |
| assert result.reward == 0.0 | |
| assert result.observation.last_action_error is not None | |
| def test_step_without_reset(self, env): | |
| with pytest.raises(RuntimeError): | |
| env.step({"action_type": "skip_resource", "resource_id": "x"}) | |
| def test_terminate_reduces_cost(self, env): | |
| env.reset("startup-cleanup") | |
| cost_before = env.current_cost | |
| env.step({ | |
| "action_type": "terminate_resource", | |
| "resource_id": "res-easy-003", | |
| "reasoning": "unused ALB", | |
| }) | |
| assert env.current_cost < cost_before | |
| def test_skip_no_cost_change(self, env): | |
| env.reset("startup-cleanup") | |
| cost_before = env.current_cost | |
| env.step({ | |
| "action_type": "skip_resource", | |
| "resource_id": "res-easy-001", | |
| "reasoning": "skip", | |
| }) | |
| assert env.current_cost == cost_before | |
| def test_lifecycle_reduces_s3_cost(self, env): | |
| env.reset("startup-cleanup") | |
| cost_before = env.current_cost | |
| env.step({ | |
| "action_type": "add_lifecycle_policy", | |
| "resource_id": "res-easy-005", | |
| "reasoning": "rarely accessed S3", | |
| }) | |
| assert env.current_cost < cost_before | |
| def test_done_on_all_actioned(self, env): | |
| env.reset("startup-cleanup") | |
| for i in range(1, 8): # 7 resources including trap | |
| rid = f"res-easy-{i:03d}" | |
| result = env.step({"action_type": "skip_resource", "resource_id": rid, "reasoning": "test"}) | |
| assert result.done is True | |
| class TestBlastRadius: | |
| def test_terminate_with_dependents_hard(self, env): | |
| """Terminating prod ALB that EC2s depend on should show blast radius.""" | |
| env.reset("enterprise-finops") | |
| result = env.step({ | |
| "action_type": "terminate_resource", | |
| "resource_id": "res-hard-009", | |
| "reasoning": "test blast radius", | |
| }) | |
| br = result.info.get("blast_radius", {}) | |
| assert br["risk_level"] != "none" | |
| assert len(br["affected_resources"]) > 0 | |
| def test_skip_no_blast_radius(self, env): | |
| env.reset("enterprise-finops") | |
| result = env.step({ | |
| "action_type": "skip_resource", | |
| "resource_id": "res-hard-001", | |
| "reasoning": "critical prod", | |
| }) | |
| br = result.info.get("blast_radius", {}) | |
| assert br["risk_level"] == "none" | |
| def test_terminate_no_dependents(self, env): | |
| env.reset("startup-cleanup") | |
| result = env.step({ | |
| "action_type": "terminate_resource", | |
| "resource_id": "res-easy-003", | |
| "reasoning": "unused ALB, no targets", | |
| }) | |
| br = result.info.get("blast_radius", {}) | |
| assert br["risk_level"] == "none" | |
| class TestState: | |
| def test_state_returns_dict(self, env): | |
| env.reset("startup-cleanup") | |
| s = env.state() | |
| assert "resources" in s | |
| assert "current_cost" in s | |
| assert s["task_id"] == "startup-cleanup" | |
| class TestClose: | |
| def test_close_resets_state(self, env): | |
| env.reset("startup-cleanup") | |
| env.close() | |
| assert env.task is None | |
| assert env.current_resources == [] | |