Files
Ai/weather/test_farm_weather_api.py
T

165 lines
6.6 KiB
Python
Raw Normal View History

2026-04-25 17:22:41 +03:30
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
2026-05-05 21:02:12 +03:30
from rag.failure_contract import RAGServiceError
2026-04-25 17:22:41 +03:30
@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]],
},
2026-05-13 16:45:54 +03:30
"source_metadata": {
"weather": {"source": "center_location_forecast", "policy": "center_location_latest_forecast"},
"agronomic_metrics": {"source": "build_ai_farm_snapshot", "policy": "cluster_block_farm_aggregated", "available": True},
},
2026-04-25 17:22:41 +03:30
}
)
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")
2026-05-13 16:45:54 +03:30
self.assertEqual(payload["source_metadata"]["weather"]["policy"], "center_location_latest_forecast")
2026-04-25 17:22:41 +03:30
@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)
2026-05-13 16:45:54 +03:30
self.assertEqual(payload["source_metadata"]["agronomic_metrics"]["policy"], "cluster_block_farm_aggregated")
self.assertEqual(payload["source_metadata"]["weather"]["policy"], "center_location_latest_forecast")
2026-04-25 17:22:41 +03:30
@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.")
2026-05-05 21:02:12 +03:30
@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")
2026-05-13 16:45:54 +03:30
@override_settings(ROOT_URLCONF="soile.urls")
class SpatialPolicySmokeTests(TestCase):
pass