from __future__ import annotations from types import SimpleNamespace from unittest.mock import patch from django.test import TestCase, override_settings from rest_framework.test import APIClient from rag.failure_contract import RAGServiceError @override_settings(ROOT_URLCONF="weather.urls") class FarmWeatherApiTests(TestCase): def setUp(self): self.client = APIClient() @patch("weather.views.apps.get_app_config") def test_farm_weather_api_returns_payload(self, mock_get_app_config): mock_service = SimpleNamespace( get_farm_weather_card=lambda **_kwargs: { "condition": "صاف", "temperature": 28.0, "unit": "°C", "humidity": 42.0, "windSpeed": 15.0, "windUnit": "km/h", "chartData": { "labels": ["2026-04-01", "2026-04-02"], "series": [[28.0, 29.0]], }, } ) mock_get_app_config.return_value = SimpleNamespace( get_farm_weather_service=lambda: mock_service ) response = self.client.post( "/farm-card/", data={"farm_uuid": "550e8400-e29b-41d4-a716-446655440000"}, format="json", ) self.assertEqual(response.status_code, 200) payload = response.json()["data"] self.assertEqual(payload["condition"], "صاف") self.assertEqual(payload["chartData"]["labels"][0], "2026-04-01") @patch("weather.views.apps.get_app_config") def test_farm_weather_api_returns_404_for_missing_farm(self, mock_get_app_config): mock_service = SimpleNamespace( get_farm_weather_card=lambda **_kwargs: (_ for _ in ()).throw(ValueError("Farm not found.")) ) mock_get_app_config.return_value = SimpleNamespace( get_farm_weather_service=lambda: mock_service ) response = self.client.post( "/farm-card/", data={"farm_uuid": "550e8400-e29b-41d4-a716-446655440000"}, format="json", ) self.assertEqual(response.status_code, 404) self.assertEqual(response.json()["msg"], "Farm not found.") @override_settings(ROOT_URLCONF="weather.urls") class WaterNeedPredictionApiTests(TestCase): def setUp(self): self.client = APIClient() @patch("weather.views.apps.get_app_config") def test_water_need_api_returns_payload(self, mock_get_app_config): mock_service = SimpleNamespace( get_water_need_prediction=lambda **_kwargs: { "farm_uuid": "550e8400-e29b-41d4-a716-446655440000", "totalNext7Days": 24.6, "unit": "mm", "categories": ["روز 1", "روز 2"], "series": [{"name": "نیاز آبی تعدیل‌شده", "data": [3.2, 4.1]}], "dailyBreakdown": [ {"forecast_date": "2026-04-01", "gross_irrigation_mm": 3.2}, {"forecast_date": "2026-04-02", "gross_irrigation_mm": 4.1}, ], "insight": { "summary": "جمع نياز آبي هفته آينده حدود 24.6 ميلي متر است.", "irrigation_outlook": "نياز آبي در حال افزايش است.", "recommended_action": "آبياري صبح زود تنظيم شود.", "risk_note": "در صورت بارش موثر برنامه بازبيني شود.", "confidence": 0.82, }, "raw_response": "{\"summary\":\"ok\"}", } ) mock_get_app_config.return_value = SimpleNamespace( get_water_need_service=lambda: mock_service ) response = self.client.post( "/water-need-prediction/", data={"farm_uuid": "550e8400-e29b-41d4-a716-446655440000"}, format="json", ) self.assertEqual(response.status_code, 200) payload = response.json()["data"] self.assertEqual(payload["farm_uuid"], "550e8400-e29b-41d4-a716-446655440000") self.assertEqual(payload["insight"]["confidence"], 0.82) @patch("weather.views.apps.get_app_config") def test_water_need_api_returns_404_for_missing_farm(self, mock_get_app_config): mock_service = SimpleNamespace( get_water_need_prediction=lambda **_kwargs: (_ for _ in ()).throw(ValueError("Farm not found.")) ) mock_get_app_config.return_value = SimpleNamespace( get_water_need_service=lambda: mock_service ) response = self.client.post( "/water-need-prediction/", data={"farm_uuid": "550e8400-e29b-41d4-a716-446655440000"}, format="json", ) self.assertEqual(response.status_code, 404) self.assertEqual(response.json()["msg"], "Farm not found.") @patch("weather.views.apps.get_app_config") def test_water_need_api_returns_structured_failure_for_invalid_llm_json(self, mock_get_app_config): mock_service = SimpleNamespace( get_water_need_prediction=lambda **_kwargs: (_ for _ in ()).throw( RAGServiceError( error_code="invalid_json", message="Water need prediction LLM response was not valid JSON.", source="llm", retriable=True, http_status=502, ) ) ) mock_get_app_config.return_value = SimpleNamespace( get_water_need_service=lambda: mock_service ) response = self.client.post( "/water-need-prediction/", data={"farm_uuid": "550e8400-e29b-41d4-a716-446655440000"}, format="json", ) self.assertEqual(response.status_code, 502) self.assertEqual(response.json()["data"]["error_code"], "invalid_json")