FairRelay / brain /tests /test_ml_effort_agent.py
MouleeswaranM's picture
Upload folder using huggingface_hub
fcf8749 verified
raw
history blame
7.35 kB
"""
Unit tests for MLEffortAgent.
Tests effort matrix computation and breakdown calculation.
"""
import pytest
from unittest.mock import MagicMock
from uuid import uuid4
from app.services.ml_effort_agent import MLEffortAgent
from app.schemas.agent_schemas import EffortWeights
class MockDriver:
"""Mock Driver for testing."""
def __init__(self, id=None, vehicle_capacity_kg=100.0, is_ev=False, battery_range_km=None, charging_time_minutes=0):
self.id = id or uuid4()
self.vehicle_capacity_kg = vehicle_capacity_kg
self.is_ev = is_ev
self.vehicle_type = "EV" if is_ev else "ICE"
self.battery_range_km = battery_range_km
self.charging_time_minutes = charging_time_minutes
class MockRoute:
"""Mock Route for testing."""
def __init__(
self,
id=None,
num_packages=10,
total_weight_kg=20.0,
num_stops=5,
route_difficulty_score=2.0,
estimated_time_minutes=60,
total_distance_km=25.0,
charging_time_minutes=0,
):
self.id = id or uuid4()
self.num_packages = num_packages
self.total_weight_kg = total_weight_kg
self.num_stops = num_stops
self.route_difficulty_score = route_difficulty_score
self.estimated_time_minutes = estimated_time_minutes
self.total_distance_km = total_distance_km
self.charging_time_minutes = charging_time_minutes
class TestMLEffortAgent:
"""Test suite for MLEffortAgent."""
def test_effort_matrix_shape(self):
"""Test that effort matrix has correct dimensions."""
agent = MLEffortAgent()
drivers = [MockDriver() for _ in range(3)]
routes = [MockRoute() for _ in range(4)]
result = agent.compute_effort_matrix(drivers, routes)
assert len(result.matrix) == 3, "Should have 3 rows (drivers)"
assert all(len(row) == 4 for row in result.matrix), "Each row should have 4 columns (routes)"
assert len(result.driver_ids) == 3
assert len(result.route_ids) == 4
def test_effort_increases_with_packages(self):
"""Test that effort increases with more packages."""
agent = MLEffortAgent()
driver = MockDriver()
route_light = MockRoute(num_packages=5, total_weight_kg=10.0)
route_heavy = MockRoute(num_packages=20, total_weight_kg=40.0)
result_light = agent.compute_effort_matrix([driver], [route_light])
result_heavy = agent.compute_effort_matrix([driver], [route_heavy])
effort_light = result_light.matrix[0][0]
effort_heavy = result_heavy.matrix[0][0]
assert effort_heavy > effort_light, "Heavier route should have more effort"
def test_effort_increases_with_difficulty(self):
"""Test that effort increases with route difficulty."""
agent = MLEffortAgent()
driver = MockDriver()
route_easy = MockRoute(route_difficulty_score=1.0)
route_hard = MockRoute(route_difficulty_score=5.0)
result_easy = agent.compute_effort_matrix([driver], [route_easy])
result_hard = agent.compute_effort_matrix([driver], [route_hard])
assert result_hard.matrix[0][0] > result_easy.matrix[0][0]
def test_capacity_penalty_applied(self):
"""Test that overloaded routes get penalty."""
agent = MLEffortAgent()
# Driver with 50kg capacity
driver = MockDriver(vehicle_capacity_kg=50.0)
# Routes with different weights
route_under = MockRoute(total_weight_kg=40.0) # Under capacity
route_over = MockRoute(total_weight_kg=70.0) # Over capacity
result_under = agent.compute_effort_matrix([driver], [route_under])
result_over = agent.compute_effort_matrix([driver], [route_over])
# Over-capacity should have significantly higher effort
assert result_over.matrix[0][0] > result_under.matrix[0][0]
def test_breakdown_components(self):
"""Test that breakdown contains all components."""
agent = MLEffortAgent()
driver = MockDriver()
route = MockRoute()
result = agent.compute_effort_matrix([driver], [route])
key = f"{driver.id}:{route.id}"
assert key in result.breakdown
breakdown = result.breakdown[key]
assert hasattr(breakdown, 'physical_effort')
assert hasattr(breakdown, 'route_complexity')
assert hasattr(breakdown, 'time_pressure')
assert hasattr(breakdown, 'capacity_penalty')
assert hasattr(breakdown, 'total')
# Total should be sum of components
expected_total = (
breakdown.physical_effort +
breakdown.route_complexity +
breakdown.time_pressure +
breakdown.capacity_penalty
)
assert abs(breakdown.total - expected_total) < 0.01
def test_stats_computed(self):
"""Test that matrix stats are computed correctly."""
agent = MLEffortAgent()
drivers = [MockDriver() for _ in range(2)]
routes = [MockRoute(num_packages=i*5 + 5) for i in range(3)]
result = agent.compute_effort_matrix(drivers, routes)
assert "min" in result.stats
assert "max" in result.stats
assert "avg" in result.stats
assert result.stats["min"] <= result.stats["avg"] <= result.stats["max"]
def test_custom_weights(self):
"""Test that custom weights affect effort calculation."""
# Default weights
agent_default = MLEffortAgent()
# Custom weights with higher package weight
custom_weights = EffortWeights(alpha_packages=5.0, beta_weight=0.1)
agent_custom = MLEffortAgent(weights=custom_weights)
driver = MockDriver()
route = MockRoute(num_packages=20, total_weight_kg=10.0)
result_default = agent_default.compute_effort_matrix([driver], [route])
result_custom = agent_custom.compute_effort_matrix([driver], [route])
# Custom should be different due to different weights
assert result_default.matrix[0][0] != result_custom.matrix[0][0]
def test_empty_inputs(self):
"""Test handling of empty inputs."""
agent = MLEffortAgent()
result = agent.compute_effort_matrix([], [])
assert result.matrix == []
assert result.stats["min"] == 0.0
assert result.stats["max"] == 0.0
assert result.stats["avg"] == 0.0
def test_snapshot_generation(self):
"""Test input/output snapshot generation for logging."""
agent = MLEffortAgent()
drivers = [MockDriver() for _ in range(2)]
routes = [MockRoute() for _ in range(3)]
input_snapshot = agent.get_input_snapshot(drivers, routes)
assert input_snapshot["num_drivers"] == 2
assert input_snapshot["num_routes"] == 3
result = agent.compute_effort_matrix(drivers, routes)
output_snapshot = agent.get_output_snapshot(result)
assert "matrix_shape" in output_snapshot
assert "min_effort" in output_snapshot