Files
Backend/yield_harvest/tests.py
T

295 lines
11 KiB
Python
Raw Normal View History

2026-04-27 00:40:59 +03:30
import json
from unittest.mock import patch
from django.contrib.auth import get_user_model
from django.test import TestCase
from rest_framework.test import APIRequestFactory, force_authenticate
from external_api_adapter.adapter import AdapterResponse
from farm_hub.models import FarmHub, FarmType
from .views import (
CurrentFarmChartView,
GrowthSimulationStatusView,
GrowthSimulationView,
HarvestPredictionView,
YieldPredictionView,
)
class CropSimulationViewTests(TestCase):
def setUp(self):
self.factory = APIRequestFactory()
self.user = get_user_model().objects.create_user(
username="farmer",
password="secret123",
email="farmer@example.com",
phone_number="09120000000",
)
self.other_user = get_user_model().objects.create_user(
username="other-farmer",
password="secret123",
email="other@example.com",
phone_number="09120000001",
)
self.farm_type = FarmType.objects.create(name="زراعی")
self.farm = FarmHub.objects.create(owner=self.user, farm_type=self.farm_type, name="Farm 1")
self.other_farm = FarmHub.objects.create(owner=self.other_user, farm_type=self.farm_type, name="Farm 2")
@patch("yield_harvest.views.external_api_request")
def test_growth_queues_simulation_task(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse(
status_code=202,
data={
"data": {
"task_id": "growth-task-123",
"status_url": "/api/crop-simulation/growth/growth-task-123/status/",
"plant_name": "گوجه‌فرنگی",
}
},
)
request = self.factory.post(
"/api/yield-harvest/crop-simulation/growth/",
{"plant_name": "گوجه‌فرنگی", "dynamic_parameters": ["DVS", "LAI"], "farm_uuid": str(self.farm.farm_uuid)},
format="json",
)
response = GrowthSimulationView.as_view()(request)
self.assertEqual(response.status_code, 202)
self.assertEqual(response.data["code"], 202)
self.assertEqual(response.data["data"]["task_id"], "growth-task-123")
mock_external_api_request.assert_called_once_with(
"ai",
"/api/crop-simulation/growth/",
method="POST",
payload={
"plant_name": "گوجه‌فرنگی",
"dynamic_parameters": ["DVS", "LAI"],
"farm_uuid": str(self.farm.farm_uuid),
},
)
@patch("yield_harvest.views.external_api_request")
def test_growth_top_level_route_queues_simulation_task(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse(
status_code=202,
data={
"data": {
"task_id": "growth-task-123",
"status_url": "/api/crop-simulation/growth/growth-task-123/status/",
"plant_name": "گوجه‌فرنگی",
}
},
)
response = self.client.post(
"/api/crop-simulation/growth/",
data=json.dumps(
{
"plant_name": "گوجه‌فرنگی",
"dynamic_parameters": ["DVS", "LAI"],
"farm_uuid": str(self.farm.farm_uuid),
}
),
content_type="application/json",
)
self.assertEqual(response.status_code, 202)
self.assertEqual(response.json()["data"]["task_id"], "growth-task-123")
def test_growth_requires_farm_uuid_or_weather(self):
request = self.factory.post(
"/api/yield-harvest/crop-simulation/growth/",
{"plant_name": "گوجه‌فرنگی", "dynamic_parameters": ["DVS"]},
format="json",
)
response = GrowthSimulationView.as_view()(request)
self.assertEqual(response.status_code, 400)
@patch("yield_harvest.views.external_api_request")
def test_growth_status_proxies_to_ai_service(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse(
status_code=200,
data={
"data": {
"task_id": "growth-task-123",
"status": "SUCCESS",
"message": "done",
"progress": {},
"result": {
"plant_name": "گوجه‌فرنگی",
"dynamic_parameters": ["DVS", "LAI"],
"scenario_id": 1,
},
"error": "",
}
},
)
request = self.factory.get("/api/yield-harvest/crop-simulation/growth/growth-task-123/status/?page=1&page_size=10")
response = GrowthSimulationStatusView.as_view()(request, task_id="growth-task-123")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["code"], 200)
self.assertEqual(response.data["data"]["status"], "SUCCESS")
mock_external_api_request.assert_called_once_with(
"ai",
"/api/crop-simulation/growth/growth-task-123/status/",
method="GET",
query={"page": "1", "page_size": "10"},
)
@patch("yield_harvest.views.external_api_request")
def test_growth_status_top_level_route_proxies_to_ai_service(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse(
status_code=200,
data={
"data": {
"task_id": "growth-task-123",
"status": "SUCCESS",
"message": "done",
"progress": {},
"result": {
"plant_name": "گوجه‌فرنگی",
"dynamic_parameters": ["DVS", "LAI"],
"scenario_id": 1,
},
"error": "",
}
},
)
response = self.client.get("/api/crop-simulation/growth/growth-task-123/status/?page=1&page_size=10")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["data"]["status"], "SUCCESS")
def test_legacy_plant_simulator_routes_are_unavailable(self):
legacy_paths = [
"/api/yield-harvest/plant-simulator/config/",
"/api/yield-harvest/plant-simulator/environment/",
"/api/yield-harvest/plant-simulator/reset/",
"/api/yield-harvest/plant-simulator/start/",
"/api/yield-harvest/plant-simulator/state/",
"/api/yield-harvest/plant-simulator/stop/",
]
for path in legacy_paths:
response = self.client.get(path)
self.assertEqual(response.status_code, 404, path)
@patch("yield_harvest.views.external_api_request")
def test_current_farm_chart_proxies_to_ai_service(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse(
status_code=200,
data={
"data": {
"result": {
"farm_uuid": str(self.farm.farm_uuid),
"plant_name": "wheat",
"scenario_id": 1,
"categories": ["day1"],
"series": {"biomass": [1.2]},
}
}
},
)
request = self.factory.post(
"/api/yield-harvest/crop-simulation/current-farm-chart/",
{"farm_uuid": str(self.farm.farm_uuid), "plant_name": "wheat"},
format="json",
)
force_authenticate(request, user=self.user)
response = CurrentFarmChartView.as_view()(request)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["code"], 200)
self.assertEqual(response.data["data"]["scenario_id"], 1)
mock_external_api_request.assert_called_once_with(
"ai",
"/api/crop-simulation/current-farm-chart/",
method="POST",
payload={"farm_uuid": str(self.farm.farm_uuid), "plant_name": "wheat"},
)
@patch("yield_harvest.views.external_api_request")
def test_harvest_prediction_proxies_to_ai_service(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse(
status_code=200,
data={
"data": {
"result": {
"date": "2026-07-15",
"dateFormatted": "15 Jul 2026",
"daysUntil": 96,
"gddDetails": {"current": 800},
}
}
},
)
request = self.factory.post(
"/api/yield-harvest/crop-simulation/harvest-prediction/",
{"farm_uuid": str(self.farm.farm_uuid)},
format="json",
)
force_authenticate(request, user=self.user)
response = HarvestPredictionView.as_view()(request)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["data"]["daysUntil"], 96)
mock_external_api_request.assert_called_once_with(
"ai",
"/api/crop-simulation/harvest-prediction/",
method="POST",
payload={"farm_uuid": str(self.farm.farm_uuid), "plant_name": ""},
)
@patch("yield_harvest.views.external_api_request")
def test_yield_prediction_proxies_to_ai_service(self, mock_external_api_request):
mock_external_api_request.return_value = AdapterResponse(
status_code=200,
data={
"data": {
"result": {
"farm_uuid": str(self.farm.farm_uuid),
"predictedYieldTons": 8.4,
"scenarioId": 1,
}
}
},
)
request = self.factory.post(
"/api/yield-harvest/crop-simulation/yield-prediction/",
{"farm_uuid": str(self.farm.farm_uuid)},
format="json",
)
force_authenticate(request, user=self.user)
response = YieldPredictionView.as_view()(request)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["data"]["predictedYieldTons"], 8.4)
def test_crop_simulation_rejects_foreign_farm_uuid(self):
request = self.factory.post(
"/api/yield-harvest/crop-simulation/yield-prediction/",
{"farm_uuid": str(self.other_farm.farm_uuid)},
format="json",
)
force_authenticate(request, user=self.user)
response = YieldPredictionView.as_view()(request)
self.assertEqual(response.status_code, 404)
self.assertEqual(response.data["code"], 404)
self.assertEqual(response.data["data"]["farm_uuid"][0], "Farm not found.")