| """ |
| Tests for Phase 2 Driver-facing API endpoints. |
| """ |
|
|
| import pytest |
| from datetime import date, timedelta |
| from uuid import uuid4 |
|
|
|
|
| class TestDriverApiSchemas: |
| """Tests for driver API schema validation.""" |
| |
| def test_delivery_log_request_valid_status(self): |
| """Valid delivery status should be accepted.""" |
| from app.schemas.driver_api import DeliveryLogRequest |
| |
| request = DeliveryLogRequest( |
| assignment_id=uuid4(), |
| route_id=uuid4(), |
| driver_id=uuid4(), |
| stop_order=1, |
| status="DELIVERED", |
| issue_type="NONE", |
| ) |
| assert request.status == "DELIVERED" |
| |
| def test_stop_issue_request_validation(self): |
| """Stop issue request should require notes.""" |
| from app.schemas.driver_api import StopIssueRequest |
| |
| request = StopIssueRequest( |
| assignment_id=uuid4(), |
| route_id=uuid4(), |
| driver_id=uuid4(), |
| stop_order=5, |
| issue_type="SAFETY", |
| notes="Dark street, no lights", |
| ) |
| assert request.issue_type == "SAFETY" |
| assert len(request.notes) > 0 |
| |
| def test_route_swap_request_creation(self): |
| """Route swap request should allow optional fields.""" |
| from app.schemas.driver_api import RouteSwapRequestCreate |
| |
| request = RouteSwapRequestCreate( |
| from_driver_id=uuid4(), |
| assignment_id=uuid4(), |
| reason="Had heavy routes for 3 days", |
| to_driver_id=None, |
| preferred_date=None, |
| ) |
| assert request.to_driver_id is None |
| assert request.preferred_date is None |
|
|
|
|
| class TestDriverStatsResponse: |
| """Tests for driver stats response schemas.""" |
| |
| def test_day_stats_model(self): |
| """DayStats should handle optional fields.""" |
| from app.schemas.driver_api import DayStats |
| |
| stats = DayStats( |
| date=date.today(), |
| workload_score=65.5, |
| fairness_score=0.82, |
| reported_stress_level=None, |
| reported_fairness_rating=None, |
| ) |
| assert stats.workload_score == 65.5 |
| assert stats.reported_stress_level is None |
| |
| def test_stats_aggregates_model(self): |
| """StatsAggregates should compute correctly.""" |
| from app.schemas.driver_api import StatsAggregates |
| |
| aggregates = StatsAggregates( |
| avg_workload=63.2, |
| avg_fairness_score=0.83, |
| avg_stress_level=3.5, |
| ) |
| assert aggregates.avg_workload == 63.2 |
|
|
|
|
| class TestTodayAssignmentResponse: |
| """Tests for today's assignment response schema.""" |
| |
| def test_full_response_structure(self): |
| """Response should include all required nested objects.""" |
| from app.schemas.driver_api import ( |
| TodayAssignmentResponse, |
| DriverDetail, |
| AssignmentDetail, |
| RouteSummaryDetail, |
| StopDetail, |
| PackageDetail, |
| ) |
| |
| driver_id = uuid4() |
| route_id = uuid4() |
| pkg_id = uuid4() |
| |
| response = TodayAssignmentResponse( |
| date=date.today(), |
| driver=DriverDetail( |
| id=driver_id, |
| external_id="ext_001", |
| name="Raju", |
| preferred_language="en", |
| ), |
| assignment=AssignmentDetail( |
| assignment_id=uuid4(), |
| route_id=route_id, |
| workload_score=65.3, |
| fairness_score=0.82, |
| explanation="Moderate route assigned", |
| route_summary=RouteSummaryDetail( |
| num_packages=22, |
| total_weight_kg=48.5, |
| num_stops=14, |
| route_difficulty_score=2.1, |
| estimated_time_minutes=145, |
| ), |
| stops=[ |
| StopDetail( |
| stop_order=1, |
| address="Some Street, Area, City", |
| latitude=12.97, |
| longitude=77.60, |
| packages=[ |
| PackageDetail( |
| id=pkg_id, |
| external_id="pkg_001", |
| weight_kg=2.5, |
| fragility_level=3, |
| priority="NORMAL", |
| ) |
| ], |
| ) |
| ], |
| ), |
| ) |
| |
| assert response.driver.name == "Raju" |
| assert len(response.assignment.stops) == 1 |
| assert response.assignment.stops[0].packages[0].weight_kg == 2.5 |
|
|
|
|
| class TestExtendedFeedbackRequest: |
| """Tests for extended feedback request.""" |
| |
| def test_extended_fields(self): |
| """Extended feedback should accept new Phase 2 fields.""" |
| from app.schemas.driver_api import ExtendedFeedbackRequest |
| |
| request = ExtendedFeedbackRequest( |
| driver_id=uuid4(), |
| assignment_id=uuid4(), |
| fairness_rating=4, |
| stress_level=5, |
| tiredness_level=3, |
| hardest_aspect="stairs", |
| route_difficulty_self_report=4, |
| would_take_similar_route_again=True, |
| most_unfair_aspect="parking", |
| comments="Too many apartments with no lift", |
| ) |
| |
| assert request.route_difficulty_self_report == 4 |
| assert request.would_take_similar_route_again is True |
| assert request.most_unfair_aspect == "parking" |
|
|