UPDATE
This commit is contained in:
@@ -11,6 +11,8 @@ from irrigation.models import IrrigationMethod
|
||||
from plant.models import Plant
|
||||
from weather.models import WeatherForecast
|
||||
|
||||
from farm_data.services import resolve_center_location_from_boundary
|
||||
|
||||
|
||||
def square_boundary_for_center(lat: float, lon: float, delta: float = 0.01) -> dict:
|
||||
return {
|
||||
@@ -93,7 +95,8 @@ class FarmDetailApiTests(TestCase):
|
||||
metric_sources = payload["soil"]["metric_sources"]
|
||||
|
||||
self.assertEqual(resolved_metrics["nitrogen"], 99.0)
|
||||
self.assertEqual(metric_sources["nitrogen"], "sensor")
|
||||
self.assertEqual(metric_sources["nitrogen"]["type"], "sensor")
|
||||
self.assertEqual(metric_sources["nitrogen"]["strategy"], "single_value")
|
||||
self.assertEqual(resolved_metrics["clay"], 22.0)
|
||||
self.assertEqual(metric_sources["clay"], "soil")
|
||||
self.assertEqual(len(payload["soil"]["depths"]), 2)
|
||||
@@ -112,6 +115,38 @@ class FarmDetailApiTests(TestCase):
|
||||
self.assertEqual(response.status_code, 404)
|
||||
self.assertEqual(response.json()["msg"], "farm یافت نشد.")
|
||||
|
||||
def test_aggregates_conflicting_metrics_from_multiple_sensors_without_overwrite(self):
|
||||
self.farm.sensor_payload = {
|
||||
"sensor-a": {
|
||||
"soil_moisture": 20.0,
|
||||
"nitrogen": 90.0,
|
||||
"status": "ok",
|
||||
},
|
||||
"sensor-b": {
|
||||
"soil_moisture": 40.0,
|
||||
"nitrogen": 110.0,
|
||||
"status": "needs-check",
|
||||
},
|
||||
}
|
||||
self.farm.save(update_fields=["sensor_payload"])
|
||||
|
||||
response = self.client.get(f"/api/farm-data/{self.farm_uuid}/detail/")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
payload = response.json()["data"]
|
||||
resolved_metrics = payload["soil"]["resolved_metrics"]
|
||||
metric_sources = payload["soil"]["metric_sources"]
|
||||
|
||||
self.assertEqual(resolved_metrics["soil_moisture"], 30.0)
|
||||
self.assertEqual(metric_sources["soil_moisture"]["strategy"], "average")
|
||||
self.assertCountEqual(
|
||||
metric_sources["soil_moisture"]["sensor_keys"],
|
||||
["sensor-a", "sensor-b"],
|
||||
)
|
||||
self.assertEqual(metric_sources["soil_moisture"]["distinct_values"], [20.0, 40.0])
|
||||
self.assertEqual(resolved_metrics["status"], ["ok", "needs-check"])
|
||||
self.assertEqual(metric_sources["status"]["strategy"], "distinct_values")
|
||||
|
||||
|
||||
class FarmDataUpsertApiTests(TestCase):
|
||||
def setUp(self):
|
||||
@@ -120,6 +155,21 @@ class FarmDataUpsertApiTests(TestCase):
|
||||
latitude="35.710000",
|
||||
longitude="51.410000",
|
||||
)
|
||||
SoilDepthData.objects.create(
|
||||
soil_location=self.location,
|
||||
depth_label="0-5cm",
|
||||
clay=20.0,
|
||||
)
|
||||
SoilDepthData.objects.create(
|
||||
soil_location=self.location,
|
||||
depth_label="5-15cm",
|
||||
clay=18.0,
|
||||
)
|
||||
SoilDepthData.objects.create(
|
||||
soil_location=self.location,
|
||||
depth_label="15-30cm",
|
||||
clay=16.0,
|
||||
)
|
||||
self.boundary = square_boundary_for_center(35.71, 51.41)
|
||||
self.weather = WeatherForecast.objects.create(
|
||||
location=self.location,
|
||||
@@ -176,7 +226,16 @@ class FarmDataUpsertApiTests(TestCase):
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertIn("farm_uuid", response.json()["data"])
|
||||
|
||||
def test_post_creates_center_location_from_boundary_when_missing(self):
|
||||
@patch("farm_data.services.update_weather_for_location", return_value={"status": "no_data"})
|
||||
@patch(
|
||||
"farm_data.services.fetch_soil_data_for_coordinates",
|
||||
return_value={"status": "completed", "depths": []},
|
||||
)
|
||||
def test_post_creates_center_location_from_boundary_when_missing(
|
||||
self,
|
||||
_mock_fetch_soil_data_for_coordinates,
|
||||
_mock_update_weather_for_location,
|
||||
):
|
||||
farm_uuid = uuid.uuid4()
|
||||
|
||||
response = self.client.post(
|
||||
@@ -203,6 +262,26 @@ class FarmDataUpsertApiTests(TestCase):
|
||||
self.assertEqual(str(farm.center_location.longitude), "50.010000")
|
||||
self.assertIsNone(farm.weather_forecast_id)
|
||||
|
||||
def test_resolve_center_location_uses_geometric_centroid_for_concave_polygon(self):
|
||||
location = resolve_center_location_from_boundary(
|
||||
{
|
||||
"corners": [
|
||||
{"lat": 0.0, "lon": 0.0},
|
||||
{"lat": 0.0, "lon": 4.0},
|
||||
{"lat": 4.0, "lon": 4.0},
|
||||
{"lat": 4.0, "lon": 0.0},
|
||||
{"lat": 1.0, "lon": 0.0},
|
||||
{"lat": 1.0, "lon": 3.0},
|
||||
{"lat": 3.0, "lon": 3.0},
|
||||
{"lat": 3.0, "lon": 1.0},
|
||||
{"lat": 0.0, "lon": 1.0},
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(str(location.latitude), "2.078947")
|
||||
self.assertEqual(str(location.longitude), "2.078947")
|
||||
|
||||
@patch("farm_data.services.update_weather_for_location")
|
||||
@patch("farm_data.services.fetch_soil_data_for_coordinates")
|
||||
def test_post_fetches_missing_location_and_weather_data(
|
||||
|
||||
Reference in New Issue
Block a user