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 irrigation.indicators import WaterStressService @override_settings(ROOT_URLCONF="irrigation.urls") class WaterStressApiTests(TestCase): def setUp(self): self.client = APIClient() @patch("irrigation.views.apps.get_app_config") def test_water_stress_api_returns_payload(self, mock_get_app_config): mock_service = SimpleNamespace( get_water_stress=lambda **_kwargs: { "farm_uuid": "550e8400-e29b-41d4-a716-446655440000", "waterStressIndex": 12, "level": "پایین", "sourceMetric": {"soilMoisture": 46.0}, } ) mock_get_app_config.return_value = SimpleNamespace( get_water_stress_service=lambda: mock_service ) response = self.client.post( "/water-stress/", data={ "farm_uuid": "550e8400-e29b-41d4-a716-446655440000", "irrigation_recommendation": {"events": [{"date": "2026-04-25", "amount": 2.5}]}, "fertilization_recommendation": { "events": [{"date": "2026-04-20", "N_amount": 45, "N_recovery": 0.7}] }, }, format="json", ) self.assertEqual(response.status_code, 200) self.assertEqual(response.json()["data"]["waterStressIndex"], 12) class WaterStressServiceTests(TestCase): @patch("irrigation.indicators.apps.get_app_config") @patch("irrigation.indicators.SensorData.objects.filter") def test_service_uses_crop_simulation_water_stress(self, mock_filter, mock_get_app_config): mock_filter.return_value.first.return_value = SimpleNamespace( farm_uuid="550e8400-e29b-41d4-a716-446655440000", soil_moisture=46.0, ) mock_service = SimpleNamespace( get_water_stress=lambda **_kwargs: { "farm_uuid": "550e8400-e29b-41d4-a716-446655440000", "plant_name": "Tomato", "waterStressIndex": 37, "level": "متوسط", "sourceMetric": {"engine": "crop_simulation"}, } ) mock_get_app_config.return_value = SimpleNamespace( get_water_stress_service=lambda: mock_service ) payload = WaterStressService().get_water_stress( farm_uuid="550e8400-e29b-41d4-a716-446655440000" ) self.assertEqual(payload["waterStressIndex"], 37) self.assertEqual(payload["sourceMetric"]["engine"], "crop_simulation") @patch("irrigation.indicators.apps.get_app_config") @patch("irrigation.indicators.SensorData.objects.filter") def test_service_raises_when_crop_simulation_fails(self, mock_filter, mock_get_app_config): mock_filter.return_value.first.return_value = SimpleNamespace( farm_uuid="550e8400-e29b-41d4-a716-446655440000", soil_moisture=46.0, ) class BrokenService: def get_water_stress(self, **_kwargs): raise RuntimeError("simulation offline") mock_get_app_config.return_value = SimpleNamespace( get_water_stress_service=lambda: BrokenService() ) with self.assertRaises(RuntimeError): WaterStressService().get_water_stress( farm_uuid="550e8400-e29b-41d4-a716-446655440000" )