This commit is contained in:
2026-05-13 16:45:54 +03:30
parent 948c062b93
commit 46fe62fa04
96 changed files with 3834 additions and 155 deletions
+98
View File
@@ -11,6 +11,10 @@ from django.test import TestCase
from rest_framework.test import APIRequestFactory
from .models import SimulationRun, SimulationScenario
from farm_data.models import PlantCatalogSnapshot, SensorData
from irrigation.models import IrrigationMethod
from location_data.models import SoilLocation
from weather.models import WeatherForecast
from .services import CropSimulationService, CropSimulationError, PcseSimulationManager
from .views import PlantGrowthSimulationView
@@ -366,3 +370,97 @@ class CropSimulationPcseIntegrationTests(TestCase):
self.assertEqual(result["result"]["engine"], "pcse")
self.assertIsNotNone(result["result"]["metrics"]["yield_estimate"])
self.assertIsNotNone(result["result"]["metrics"]["biomass"])
class CropSimulationCanonicalSnapshotTests(TestCase):
def setUp(self):
self.location = SoilLocation.objects.create(latitude="35.700000", longitude="51.400000")
self.weather = WeatherForecast.objects.create(
location=self.location,
forecast_date=date(2026, 4, 10),
temperature_min=12.0,
temperature_max=24.0,
temperature_mean=18.0,
humidity_mean=55.0,
precipitation=1.0,
et0=3.5,
)
self.plant = PlantCatalogSnapshot.objects.create(backend_plant_id=401, name="wheat")
self.irrigation_method = IrrigationMethod.objects.create(name="drip")
self.farm = SensorData.objects.create(
farm_uuid="550e8400-e29b-41d4-a716-446655440000",
center_location=self.location,
weather_forecast=self.weather,
irrigation_method=self.irrigation_method,
)
self.farm.plants.add(self.plant)
@patch("crop_simulation.services.build_ai_farm_snapshot")
def test_build_simulation_payload_from_farm_uses_aggregated_metrics(self, mock_snapshot):
from crop_simulation.services import build_simulation_payload_from_farm
mock_snapshot.return_value = {
"farm_uuid": str(self.farm.farm_uuid),
"farm_metrics": {
"resolved_metrics": {
"soil_moisture": 36.0,
"ndwi": 0.31,
"nitrogen": 21.0,
"phosphorus": 11.0,
"potassium": 17.0,
"soil_ph": 6.8,
"electrical_conductivity": 1.4,
}
},
"source_metadata": {
"farm_metrics": {
"canonical_source": "farmer_block_aggregated_snapshot",
"aggregation_strategy": "farmer_block_mean",
}
},
}
payload = build_simulation_payload_from_farm(farm_uuid=str(self.farm.farm_uuid), plant_name="wheat")
self.assertEqual(payload["soil"]["soil_moisture"], 36.0)
self.assertEqual(payload["site_parameters"]["NAVAILI"], 21.0)
self.assertEqual(payload["soil"]["phosphorus"], 11.0)
self.assertEqual(payload["source_metadata"]["farm_metrics"]["canonical_source"], "farmer_block_aggregated_snapshot")
@patch("crop_simulation.services.build_ai_farm_snapshot")
def test_build_simulation_payload_from_farm_handles_missing_block_metrics(self, mock_snapshot):
from crop_simulation.services import build_simulation_payload_from_farm
mock_snapshot.return_value = {
"farm_uuid": str(self.farm.farm_uuid),
"farm_metrics": {"resolved_metrics": {}},
"source_metadata": {"farm_metrics": {"status": "missing"}},
}
payload = build_simulation_payload_from_farm(farm_uuid=str(self.farm.farm_uuid), plant_name="wheat")
self.assertEqual(payload["site_parameters"]["WAV"], 40.0)
self.assertEqual(payload["source_metadata"]["farm_metrics"]["status"], "missing")
@patch("crop_simulation.services.build_ai_farm_snapshot")
def test_run_single_simulation_stores_weather_provenance(self, mock_snapshot):
mock_snapshot.return_value = {
"farm_uuid": str(self.farm.farm_uuid),
"farm_metrics": {"resolved_metrics": {"soil_moisture": 35.0, "ndwi": 0.3}},
"source_metadata": {
"farm_metrics": {"canonical_source": "farmer_block_aggregated_snapshot"},
"weather": {"policy": "center_location_latest_forecast"},
},
}
service = CropSimulationService()
with patch.object(service.manager, "run_simulation", return_value={"engine": "pcse", "metrics": {}, "daily_output": [], "summary_output": [], "terminal_output": []}):
result = service.run_single_simulation(
farm_uuid=str(self.farm.farm_uuid),
plant_name="wheat",
agromanagement=build_agromanagement(),
)
self.assertEqual(result["result"]["source_metadata"]["weather"]["policy"], "center_location_latest_forecast")
run = SimulationRun.objects.get()
self.assertEqual(run.result_payload["source_metadata"]["farm_metrics"]["canonical_source"], "farmer_block_aggregated_snapshot")